reelsaw
This MCP server exposes Reelsaw’s AI video-clipping pipeline and management API to agents: create projects, edit clips/transcripts, manage media assets/templates, and administer sharing, webhooks, and settings.
Projects: create from a URL or upload, list/search, wait for completion, retry, re-analyze, refine, inspect events, and delete/restore/purge.
Clips: create, edit bounds/title/hook/caption/style/framing/layers, rerender, delete/restore/purge, and inspect full render details.
Transcripts: read timed text, import SRT/VTT, list/review fixes, add corrections/cuts, and download caption/transcript files.
Library assets: search local/catalog/providers, add/update/delete/restore assets, check usage, and set default intro/outro.
Layer templates: list/save/update/delete/restore templates and apply them to clips.
Sharing/export: create and revoke download links, export clip zips, and generate issue reports.
Webhooks: create/update/delete/test endpoints, rotate secrets, list deliveries, and resend failed deliveries.
Account/admin: manage project defaults, style/source-text settings, decision learning, email preferences, billing, instance settings, workers, queues, failures, retries, releases, and update checks.
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.
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. A hosted service at app.reelsaw.com runs the same code (Free, then $12 / $29 / $59 a month, metered in source minutes).
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"; shot cuts are detected on every clip, and a multi-camera edit that alternates a close-up with a wide shot every second or two changes layout at each cut): 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, the webcam tile below — the picture-in-picture box of a Zoom, Teams, Meet or OBS recording, not a face-sized crop that reaches into the slides), or fit (whole frame over a blurred background when there is no face, e.g. graphics and b-roll, or when three or more people share the frame). 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, per clip or per section, including a hand-set crop. 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. In split and stack sections that last 2.5 s or more, captions sit on the line between the two panes instead of on the lower speaker (a switch turns it off). 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, layers) 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; right-click for Set crop… (a box on the source, or
crop/crop2/contentCroponupdate_clip); "Use for all clips…" copies one clip's framing to the project (apply_framing). Add, drag and remove transitions; ⌘/Ctrl+Z / ⇧⌘Z undo and redo every edit.Deletes can be undone – deleting a project or a clip (card ⋯, the selection bar, the editor, ⌘K) stops its work and hides it. The toast always offers Undo, Delete forever, and See deletions. Everything restorable lives on Deleted (account menu) as one selectable list: each row says when it was deleted and when it is deleted forever, and a compact bar restores the selection or deletes it forever. Storage still counts until you delete it forever (MCP
list_deletedpluspurge_project/purge_clip/purge_asset/purge_layer_template;reelsaw purge-project,purge-clip,library purge,templates purge). Minutes, hourly creates and first-video-free are never refunded. 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. The same through MCP (delete_clip,delete_clips,restore_project,restore_clip,list_deleted) and the CLI (reelsaw deleted,restore,delete-clip,delete-clips,restore-clip,purge,purge-project,purge-clip).Learns from your decisions – what you accept, reject, cut, correct and edit is kept in a decision log (with the words or clip text it was about, the models that proposed it and a fingerprint of the source video) that outlives deleted projects: cuts you rejected are shown to the filler detector as examples to keep, and an export turns your decisions into eval cases (
reelsaw decisions export,export_decisions, thedecisionssuite). Settings → Learning turns it off or forgets everything; deleting a project (or "Delete forever") can forget what it learned from that project, applied when it is purged, even automatically. It never leaves your instance. See docs/specs/decision-log.md.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 project or clip), 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.Share links – a clip's ⋯ menu copies a link anyone can download it from without signing in (the project and selection menus do the same for the zip), for schedulers (Buffer, Metricool), Instagram's
video_url, Zapier/Make file fields or a person. The link answers with the file itself (a plain 200, no redirect), serves the clip's latest render, lasts 90 days by default (MEDIA_LINK_TTL_DAYS; "Never" whereMEDIA_LINK_ALLOW_NEVER), and can be revoked one at a time, per clip or project, or all at once under Settings → Share links. MCPget_media_links,list_media_links,revoke_media_link;reelsaw media-links. See docs/specs/media-links.md.Webhooks – Settings → Webhooks sends signed JSON (Standard Webhooks:
webhook-id,webhook-timestamp,webhook-signature) to your URLs onproject.created,project.done(every clip with share links and the zip),project.failed,clip.doneandclip.failed, so n8n, Zapier, Make or a script can act the moment clips are ready instead of polling. Deliveries commit with the event, are retried 8 times over about 22 hours, and an endpoint that fails for 3 days is turned off with an email; each has a delivery log with the request, the answer and Resend. A project'smetadata(create_project) comes back in every webhook for it. MCPcreate_webhook/delete_webhook(how a Zapier or Make app subscribes),list_webhooks,update_webhook,rotate_webhook_secret,test_webhook,list_webhook_deliveries,resend_webhook_delivery;reelsaw webhooks. See docs/specs/webhooks.md.SRT / VTT in and out – every rendered clip's ⋯ menu offers its captions as
.srtor.vtt(the same lines and times as the video, intro included, even when the style has captions off), and "Export all" adds them next to each clip asclips/NN-title.srtand.vtt; clips rendered before this feature need a re-render first. The project's ⋯ menu ("Transcript files…") downloads the transcript the same way (VTT can carry a timestamp before every word) and imports a subtitle file you already have: right after creating a project (only the video is fetched) or on a done or failed one (it cleans the transcript up and picks clips again). Imported cues become segments and their words are spread over the cue by length; the render re-aligns words to the audio. AlsoGET /api/clips/:id/captions.srt|vtt,GET /api/projects/:id/transcript.srt|vtt(?words=1for VTT word times), the MCP toolsget_clip_captions,get_project_transcript_fileandimport_transcript, andreelsaw captions,transcript-fileandimport-transcript.
Library, layers and templates
Library – intros and outros, logos, stickers, b-roll, music and sound effects (PNG, JPG, GIF, WebP, SVG, video, audio). Drop many files at once (duplicates are detected), search your items plus a bundled catalog and, with an admin key, Pexels, Pixabay, Freesound, Iconify, Giphy and Klipy. 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 intro/outro, uses none or a specific item; each clip can follow the project, use none or pick its own. An unusable asset is skipped with a plain-language event instead of failing the clip.
Layers – one timeline lane for image/video overlays, text and sound (
update_clip { layers },reelsaw clip-layers): position, size, opacity, fonts shipped in the image, several music tracks with fade, loop and sidechain ducking under speech. Right-click a layer on the 9:16 preview to edit, centre, reorder, copy or remove; double-click text to retype it. ⌘C / ⌘V copy and paste layers.Layer templates – save a look once (a logo pop in the first seconds, a follow card at the end, a watermark or a music bed, plus an intro and outro) with timing from the start, the end, the whole clip or a share of its length, then apply it to selected clips or set it on a project so every new clip gets it (
list_layer_templates,apply_layer_template,reelsaw templates).
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 layers and framing, create and re-render clips, manage the library and layer templates, and export the results. On a hosted plan the same tools are available, including Free. 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,set-password,library,templates,apply-framing,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 a note when clips finish if you've stepped away) 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. A long stage saves its parts as they finish (each 3-minute window of Finding moments), so a retry or a timeout on a slow local model continues where it stopped instead of starting over, and a timeout says how far it got (
LLM_CALL_TIMEOUT_SECONDS,STAGE_IDLE_TIMEOUT_MINUTES). Run extraworkercontainers 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, with stage, download and transcription time per second of video and per-proxy download health.
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. Overlay stacking (Select inside a Dialog, z-index, portals) and the mobile viewport (h-dvh, not h-screen) are docs/UI.md. Agent instructions live in AGENTS.md (the only agent file; see the process principles).
Install (no source needed)
Needs Docker (Docker Desktop on macOS and Windows). One command: it looks at the machine (RAM, GPU, Docker's memory, free disk, an Ollama already running and the models it has, the port), proposes a setup, asks three questions in a terminal (local Ollama or a hosted provider, which model, go ahead) and installs Ollama for you (Homebrew, ollama.com or winget) if you pick local and it is missing:
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, starts everything and waits until http://localhost:3000 answers (or the next free port).
Fully local is the default when the machine can carry a useful model: qwen2.5:14b (~9 GB) with
24 GB of RAM or a 12 GB GPU, qwen2.5:7b from 12 GB, gemma3:4b below that, and a good model that
Ollama already has is reused instead of downloaded; with an NVIDIA GPU and the container toolkit,
Ollama and Speaches run on the GPU (and renders encode with NVENC; see "Using a GPU" below). Hosted
providers (OpenAI, Anthropic, Google, Groq, Vercel AI Gateway) are a choice in the same prompt: the
key is asked for and never echoed, and Anthropic and Google pair with local Speaches for
speech-to-text. Without a terminal, or with REELSAW_YES=1, the proposed answers are taken;
REELSAW_AI, REELSAW_LLM, REELSAW_PORT and friends answer in advance and REELSAW_DRY_RUN=1
prints the plan and stops (every option is listed at the top of the script).
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=2Each worker keeps its own scratch copies of the sources and renders it works on. With an S3 store
they are a cache: idle copies of finished projects are evicted after SCRATCH_CACHE_HOURS (24), a
job short of disk evicts the least recently used ones first, and a worker that still cannot make
room hands the job to a worker that has it and stops taking media jobs until its disk recovers
(Settings → System → Workers shows "disk full"). A job leases the scratch it is about to write
against its volume's live leases before the first byte lands, so two large ingests on one box
cannot both pass the free-space check and both run out mid-download: the second waits for the
first. Processes sharing a volume (the app and worker replicas of one host) share one ledger;
a worker on another host never contends.
Use 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.
Using a GPU
Three things can use one, each in its own container, so the GPU is a Compose override rather than
a different image: docker-compose.gpu.yml reserves every NVIDIA device for speaches, ollama,
app and worker. Host side you need the NVIDIA driver (nvidia-smi works) and the
NVIDIA Container Toolkit
(sudo nvidia-ctk runtime configure --runtime=docker && sudo systemctl restart docker; on Windows,
Docker Desktop on WSL2 with the Windows driver only). Then in .env:
# Linux/macOS (colon). On Windows use a semicolon: docker-compose.yml;docker-compose.gpu.yml
COMPOSE_FILE=docker-compose.yml:docker-compose.gpu.yml
SPEACHES_IMAGE=ghcr.io/speaches-ai/speaches:latest-cuda
WHISPER_MODEL=Systran/faster-whisper-large-v3 # or deepdml/faster-whisper-large-v3-turbo-ct2
TRANSCRIPTION_MODEL=openai:Systran/faster-whisper-large-v3and docker compose --profile local-ai up -d as before. What changes:
Transcription is the big one: faster-whisper on CUDA runs
large-v3in a fraction of real time, wheresmallon a CPU was about real time (the transcribe factor in the table below).The language model uses the card when Ollama runs in the
ollamacontainer (--profile ollama). A native Ollama (macOS, or Linux on the host) already uses the GPU on its own.Renders encode with
h264_nvencinstead of libx264:FFMPEG_ENCODER=autoprobes it at boot and keeps libx264 when the card is not there. Filters (crops, blur, captions) still run on the CPU, and render was already the short stage, so expect seconds, not minutes. A hardware encode that fails mid-clip (NVENC session limit, driver reset) is redone with libx264 for that clip.The on-device models (face, text, alignment) stay on the CPU by default.
ONNX_EXECUTION_PROVIDER=cudamoves them, but the published image carries no CUDA libraries for onnxruntime, and on Apple silicon CoreML measured slower than the CPU for all three; seedocs/CONFIG.md.
Settings → System → Overview and docker compose exec app reelsaw machine show the GPU the app
process sees, the encoder in use and why, and where each on-device model runs. Workers (and
reelsaw workers) lists every API and worker replica with its specs and what it is processing —
needed when the HTTP process is not the one doing the work. macOS has no CUDA in
Docker: run Ollama natively for Metal, and leave Speaches on the CPU (or point OPENAI_BASE_URL at a
whisper.cpp or MLX server running on the host, which speaks the same API).
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. Finding moments saves each part it finishes, so on a long video and a slow model a retry or a timeout continues from the last finished part instead of starting over, and the project shows "N of M parts, about X left".
¹ 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 and for a public instance that already confirms email. |
| 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 of the password? Sign-in has Forgot
password when email is on. Without email, an operator sets a new one from the shell (docker compose exec app reelsaw set-password you@example.com); --must-change makes them pick their own
at the next sign-in, without asking for the temporary password (the session is the proof they knew
it). To promote an account from the shell: docker compose exec app reelsaw make-admin you@example.com.
Email (EMAIL_DRIVER=smtp|resend, EMAIL_FROM, SMTP_URL or RESEND_API_KEY) turns on approval
notices, password reset, the ready note and, with REQUIRE_EMAIL_VERIFICATION=true, verification
before the first sign-in. Confirmation and reset links work for 24 hours and only once; an expired
link lands on a page that sends a new one. Sign-in has Forgot password? when email is on;
choosing a new password signs out other devices. Without email everything else works; approvals
are handled on the Users page.
The ready note is one email when projects finish and you have not come back to see them. The first
project to finish schedules it (EVENT_PROJECT_DONE_READY_EMAIL_DELAY_MINUTES, default 20, Settings → System →
Operations); another project that finishes while it is waiting joins the same note instead of
sending its own. Opening the app, or an API or MCP call, counts as being here, so clips you stayed to
watch are left out of the note. The first project, and later the 10th, 25th, 50th and 100th,
get a line of their own. Nothing is sent when email is off. Each note has a one-click unsubscribe
(the List-Unsubscribe header mail apps show, and a link in the footer); people can also turn it
off under Settings → Account, with set_email_preferences over MCP, or an operator with
reelsaw email-prefs <email> --ready off. Optional mail is split into topics (today ready), each with its own switch and its own unsubscribe link, so later kinds of mail can be turned off one at a time.
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_SOURCE_MINUTES_PER_MONTH,MAX_NEW_PROJECTS_PER_HOUR,MAX_STORAGE_MB,MAX_LIVE_JOBS_PER_USER(jobs queued or running from one account's own requests),MAX_RERENDERS_PER_HOUR(re-renders, hand-made clips and re-runs such as re-analyze and refine, per hour),MAX_REQUESTS_PER_MINUTE,MAX_REQUESTS_PER_HOURandMAX_WEBHOOKS_PER_USER(0 = unlimited), with per-user overrides on the Users page. Storage counts sources, uploads (an upload already copied into a project counts once), rendered clips and intros/outros, and is checked on every way a file arrives. A refusal is a sentence that says what to do ("Monthly limit of 300 minutes reached (312 used); resets on 1 November"). The monthly window is the account's billing period when it has a plan, else the UTC calendar month. On an account with a minutes limit, a link whose site reports its length is refused when the project is created (with the upgrade offer), so no project is made for it. Otherwise the length is checked again before the download and once the file is probed, so an over-long video fails the project with that reason, once, without being fetched again. The first video of a plan with a free allowance is the first one whose length is known.Watermark:
WATERMARK_NON_ADMINS(default on) burns the logo (WATERMARK_LOGO_PATH) withWATERMARK_TEXT("reelsaw.com") under it into the clips of accounts that are not admins; a paid plan removes it, and an admin can switch it per user on the Users page (Limits). Decided at render time, so a re-render after the change applies it. Clips already rendered keep what they were rendered with.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 (the store object and the local copy); rows and history stay. A clip re-renders from its source; once the source is removed, "fetch again" (Retry on the project) downloads it first.reelsaw retentionruns a sweep by hand. With an S3 store,SCRATCH_CACHE_HOURS(24) is how long a worker keeps its local copies of stored files once a project is finished and idle; the bucket copy stays and comes back when a job needs it.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, sign-in and password reset.Free-tier abuse (all off unless set;
apps/server/src/abuse.ts):MAX_SIGNUPS_PER_IP_PER_DAYcaps accounts per network address (behind a proxy,TRUST_PROXYreadsCF-Connecting-IP,X-Real-IP,X-Forwarded-For);BLOCK_DISPOSABLE_EMAILSrefuses temporary-address domains; one account per real mailbox (john.doe+x@gmail.comisjohndoe@gmail.com);MAX_REQUESTS_PER_MINUTE/_HOURcap changes (API mutations, MCP tool calls) per account, with plan and per-user overrides like the other quotas. An hourly pass flags accounts that share a sign-up address, arrive in bursts or use a temporary domain; the Users page shows the flags ("Flagged only"),reelsaw abuselists them, and nothing is suspended automatically. Every refusal is a sentence.yt-dlp from a datacentre: YouTube refuses many cloud IPs.
YTDLP_PROXYis one URL or an operator-ranked pool (a home Pi, a cheap VPS, a paid proxy).{session}in a URL is replaced per download so a residential gateway can sticky-session one video and rotate the next. Reliability is a circuit breaker on each candidate and never changes the ranking among healthy ones.YTDLP_COOKIES_FILEhelps too; a blocked download fails with "upload the file instead".reelsaw ytdlp-proxiesshows the pool.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. The consent page shows the address the approval returns to, registrations are capped at 20 per network address per day, and each person lists and revokes the apps they allowed under Settings → Account → Connected apps.Client address behind a proxy (
TRUST_PROXY,TRUSTED_PROXY_HEADER,TRUSTED_PROXY_HOPS): the sign-up cap and the registration limit key on the client address. With the defaultx-forwarded-forit is the entryTRUSTED_PROXY_HOPSplaces from the right (1 behind Caddy, 2 behind Cloudflare and Caddy), so addresses a client prepends do not count; the other headers are read only when selected.
Billing (enterprise edition)
The hosted service at app.reelsaw.com adds plans and billing through Stripe. That code lives in
apps/server/src/ee and apps/web/src/ee under its own licence (LICENSING.md),
ships in the same image, and runs only with REELSAW_EE=true plus STRIPE_SECRET_KEY and
STRIPE_WEBHOOK_SECRET. Nothing else changes for a self-hosted install.
A plan is a named set of the limits above (
ee/billing/plans.ts); the account's plan sits between the instance setting and the admin's per-user override. Free is a plan too: what an account with no, or a lapsed, subscription gets.Stripe is the source of truth. A webhook (
POST /api/billing/webhook) is acknowledged only once its event row and abilling.syncjob have committed together; the job rewrites the account's row from Stripe, so events that arrive late, twice or out of order converge. A daily reconcile andreelsaw billing syncrepair anything a lost webhook left behind.Settings → Plan and billing shows the plan, the period's usage and the plan grid; Checkout and the Billing Portal are Stripe's pages.
get_billing,billing_checkout_urlandbilling_portal_urldo the same over MCP;reelsaw billing <email>shows the row, Stripe's view and the last webhook events.A failed payment keeps the plan for
BILLING_GRACE_DAYS(7), then the account is on Free. Admins can grant a plan without Stripe (Users → Limits → Plan, orreelsaw billing set-plan). A lapse or downgrade does not re-watermark clips already rendered; only new renders get the watermark. An account that already has a live Stripe subscription is sent to the Billing Portal to change it, never to a second Checkout.Setting up a Stripe account:
pnpm --filter @reelsaw/server stripe:setup --webhook --portal(rebuilds@reelsaw/sharedfirst) creates the products, prices (by lookup key), webhook endpoint and portal configuration from the plan list, idempotently. Developing without a Stripe account:pnpm --filter @reelsaw/server stripe:mockstands in for api.stripe.com (STRIPE_API_BASE=http://host.docker.internal:4242) andtest/billing-stack.test.tsdrives the whole lifecycle through signed webhooks.
Design and decisions: docs/specs/ee.md.
MCP: drive Reelsaw from an agent
Reelsaw is an MCP server (Model Context Protocol, Streamable HTTP) at /api/mcp. With
MCP_OAUTH=true (on at app.reelsaw.com), a client needs only the address: you sign in and approve
it in the browser, and Settings → API keys and MCP shows the command and connector address.
claude mcp add --transport http reelsaw https://your-host/api/mcp # then /mcp in Claude Code to sign inIn claude.ai or Claude Desktop, add a custom connector with the same address.
Scripts, and clients that cannot sign in, use an API key. Create one in Settings → API keys and MCP (shown once) and point the 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_…" } } } }Key permissions. A key acts as you, with one exception: the instance-administration tools
(get_instance_settings, set_instance_settings, list_workers, get_queue, list_failures,
get_failure, retry_failures, check_for_update, and instance-wide report_issue) need a key
created with Allow instance administration (admin tools over MCP), a checkbox admins see in
Settings. Keys are created without it by default, and a key that lacks it is refused with "This
key cannot change instance settings". Keys created before permissions existed were given the administration grant when the
database upgraded, so they keep working; it shows on the key in Settings, where you can revoke it
or replace the key. A key with no permission record is never an administrator.
Connectors that sign in through OAuth (MCP_OAUTH=true) never get the admin tools, whoever
signs in.
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"] } } }Reelsaw is listed on the MCP registry as
io.github.osbytes/reelsaw (server.json, published on every release), so registry-aware clients
can install the bridge from the image without a running container to exec into:
{ "mcpServers": { "reelsaw": { "command": "docker", "args": ["run", "-i", "--rm", "-e", "REELSAW_URL=https://your-host", "-e", "REELSAW_API_KEY=rs_…", "ghcr.io/osbytes/reelsaw", "reelsaw", "mcp"] } } }Automation tools can call the same endpoint without an MCP client: it is stateless and answers plain
JSON, so a tools/call POST is one HTTP request. docs/n8n has ready-made n8n
workflows that clip every new upload on a YouTube channel and, on the signed project.done webhook,
queue each clip in Buffer (or upload it to YouTube Shorts), with a polling variant for an n8n that
cannot receive webhooks, docs/make builds the same pipeline from Make's own modules
(MCP Client and Custom webhook), and integrations/zapier
is the source of a Zapier app built on the same tools (instant triggers through create_webhook). To be told when clips are ready instead of
waiting, add a webhook (create_webhook, or Settings → Webhooks) and verify each delivery with any
Standard Webhooks library:
import { Webhook } from "standardwebhooks";
const event = new Webhook(process.env.REELSAW_WEBHOOK_SECRET).verify(rawBody, request.headers); // throws if forged or stale
if (event.type === "project.done") for (const clip of event.data.clips) console.log(clip.title, clip.shareUrl);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 (anything yt-dlp fetches) or a file you uploaded: POST /api/upload with the file as the body, header x-filename and your API key as Authorization: Bearer, then pass the uploadId it returns. |
| Rename a project and/or change its saved settings (focus, instructions, clip length, maxClips, caption style, framing, pauses, refineEntities, refineDisfluency, disfluencyLlm, refineScenes); 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. |
| The captions of a clip's last render as an SRT or WebVTT file: the same lines and times as the video (intro included), even when the style has captions off. |
| The project transcript as an SRT or WebVTT subtitle file, one cue per transcript segment, in source-video seconds. |
| Use an SRT or WebVTT file as the project's transcript instead of transcribing: right after create_project (only the video is fetched) or on a done or failed project (it then re-cleans the transcript and picks clips again; accepted and rejected fixes, cuts and corrections on the old transcript are lost for good). |
| 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 (the same events the Activity panel shows; live progress ticks are not stored): stage starts and completions, clip renders, retries, failures with reasons. |
| Everything about one clip: text, bounds, scores, emphasis, layers (assets, text, sounds), render diagnostics, video/thumbnail/editor links, and what the next render will use with where each comes from: style { own, effective, from: clip|project|default }, framing { own, effective: { mode, adjust, sections }, from }, bumpers { own, effective } (intro/outro). |
| Edit one clip (3 s-10 min): only the fields you pass change; style, layoutSections and layers replace the whole value (null = project's / none). |
| Add a clip from a time range of the source (needs a transcript). |
| Delete one clip of a live project; a render in progress stops. |
| Delete several clips of one live project in one step (the selection bar's Delete); renders in progress stop. |
| 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). |
| Links anyone can download without an Authorization header, for a scheduler (Buffer, Metricool), Instagram's video_url, Zapier/Make or a person. |
| Your share links, newest first. |
| Turn share links off now: one (linkId), a clip's (clipId), a project's (projectId) or all of yours (all: true). |
| Your webhook endpoints. |
| Subscribe a URL to events: project.created, project.done (with every clip, share links and the zip), project.failed, clip.done (also re-renders), clip.failed. |
| Change a webhook's url, events or description, or turn it on or off (enabled). |
| Remove a webhook (unsubscribe); nothing more is sent to it and its delivery log goes with it. |
| A new signing secret for a webhook. |
| Send a webhook.test delivery now and wait for the answer. |
| The delivery log, newest first. |
| Send a delivery again (a new series of attempts, same webhook-id and body, signed afresh). |
| A download link for a zip of the project's rendered clips with YouTube/TikTok metadata. |
| A download link for an issue-report zip (the same file Report an issue in the app saves; admins may include instance-wide diagnostics). |
| 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. |
| Re-run refine steps on the existing transcript: entities (name spelling), disfluency (filler and repeat cuts), scenes (shot cuts); all three when steps is omitted. |
| Pick clips again from the existing transcript (needs one), optionally with new settings. |
| Find assets. |
| Add from exactly one source: a public url or an uploadId (video, image, GIF, SVG or sound) becomes one of your library uploads; a search_assets catalog / provider hit (provider + externalId) materializes one instance-shared copy (checksum verified, license recorded; not listed in your library). |
| Rename one of your own library items, replace its tags, or change how long a still image shows (deleted items too; shared catalog and provider items cannot be changed). |
| Delete one of your uploads: it leaves the library and your defaults and goes to Deleted. |
| Bring one of your deleted library items back (the id from delete_asset or list_deleted); restoring an item that is not deleted changes nothing. |
| Where a library item is used: as intro, outro, overlay or music on projects and clips (replaced clips left out), and in layer templates. |
| Make a library item your default intro or outro for projects you create from now on (assetId null clears it). |
| 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. |
| Your layer templates (layers that fit any clip length, plus an optional intro / outro), newest first. |
| Create a template from exactly one of clipId (that clip's layers: spanning = fill, touching the start = head, touching the end = tail, else anchored to the nearer edge; plus the intro and outro the clip renders with) or layers (each with a timing, see list_layer_templates; [] with bumpers = an intro / outro only template). |
| Rename a layer template, replace its layers (the whole list, each with a timing) and/or replace its intro / outro (bumpers; null = it sets neither); a field left out is untouched. |
| Delete a template (it goes to Deleted) and drop it from your project defaults; clips that already got its layers keep them. |
| Bring back a deleted layer template (the id from list_layer_templates deleted or list_deleted). |
| Make one clip's framing the whole project's, for a recording whose layout never changes (a slide deck with a webcam tile, a fixed camera): the clip's section at |
| Write a template onto clips of one project (up to 200 clipIds, or all): its layers fitted to each clip's length, and the intro / outro it sets as each clip's own. |
| Delete one of your projects and all its clips; work in progress stops. |
| Permanently remove a deleted project and its files so the storage is freed (find it with list_deleted or list_projects deleted: true). |
| Bring back a deleted project with its clips and files (find it with list_deleted or list_projects deleted: true); restoring a project that is not deleted changes nothing. |
| Bring back a deleted clip or one a re-analyze replaced (list_deleted or get_project → replacedClips); it goes to the end of the project's clips. |
| Restorable deletes (the Deleted page): one newest-first list of projects, clips of live projects, library items and templates. |
| Permanently remove a deleted clip of a live project and its rendered file so the storage is freed (find it with list_deleted). |
| Permanently remove an already-deleted library upload and its files so the storage is freed (find it with list_deleted). |
| Permanently remove an already-deleted layer template (find it with list_deleted). |
| Admins only: is a newer Reelsaw published? |
| Published Reelsaw versions from GitHub (reelsaw.com/releases): tag, date, a short summary and the change notes. |
| Admins only: the instance settings in force (sign-up mode, email verification, captcha, legal links, quotas, upload limits, retention, stall watchdog, update check, health details) and where each comes from. |
| Admins only: every Reelsaw process that has checked in (API, worker, combined app): CPU, memory, disk (free/total MB, -1 = unmeasurable; diskLeasedMB = claimed by jobs in flight), GPU, render slots, queues it listens on, and its jobs. |
| Admins only: one failed project or clip (title, owner email, stage, full recorded reason, when). |
| Admins only: waiting, running and retrying job counts per pipeline stage with when the longest wait began (oldestWaitingAt), plus the jobs currently in flight (project title, attempt, started, and a retrying job's lastError). |
| Admins only: failed projects and clips across the instance (owner email, stage, reason, when). |
| Admins only: retry matching failed projects and clips through the same lifecycle as retry_project / rerender_clip (never a raw queue poke). |
| Admins only: change instance settings without a restart; every process applies them within seconds and the change is audited. |
| Which optional emails you get, by topic. |
| Turn topics of optional email on or off; omitted topics stay as they are. |
| Hosted instances: your plan and subscription, the billing period, the limits in force with where each comes from (instance, plan, an admin's override), what you have used this period, whether renders carry a watermark, and the plans on offer. |
| Hosted instances: a Stripe Checkout URL for a plan (or, when the account already pays, the Billing Portal page that confirms the plan change). |
| The fixes Reelsaw made or suggests in a project's transcript: misheard names, fillers and repetitions to cut, and your own cuts and corrections. |
| Accept or reject suggested transcript fixes (ids from list_transcript_flags), optionally with your own replacement text for an accepted name fix. |
| Make captions show "text" instead of the words spoken between startSec and endSec (a misheard name, say); the span must cover whole words. |
| Remove the words spoken between startSec and endSec from the transcript, so captions and the rendered video skip them; the span must cover whole words. |
| The settings every new project starts with (Settings, Project defaults): language, vocabulary, instructions, focus, clip lengths, pauses, caption look and refine steps. |
| Replace the settings every new project starts with; existing projects keep theirs. |
| Hide or keep text burned into the source video (captions, logos) for the whole project: hide covers it, keep leaves it, always shows it. |
| Change the caption/hook look for the whole project (font, colors, size, position, words per line). |
| Your decision log: what you accepted, rejected, cut, corrected, edited, deleted or restored, newest first, kept after a project is deleted so Reelsaw learns from it. |
| A page of your decision log in export form, oldest first, for evals. |
| Delete entries from your decision log so Reelsaw stops learning from them: one project's (projectId, live or already deleted forever) or, without projectId, all of them. |
| Whether Reelsaw records your decisions (accepts, rejects, cuts, clip edits) to learn from (Settings → Learning, on by default). |
| Hosted instances: a Stripe Billing Portal URL to see invoices, change the card or cancel at period end. |
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 |
| running version, latest published release, how to upgrade |
| published versions from GitHub (reelsaw.com/releases / list_releases) |
| 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) |
| set an account's password from a prompt (or two stdin lines); |
| run the retention sweep now (SOURCE_RETENTION_DAYS / CLIP_RETENTION_DAYS) |
| restorable deletes as one list with their purge date. No email: projects across the install. With email: that account (the Deleted page / list_deleted) |
| 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) |
| delete several clips of one project at once (same as the selection bar, clips.deleteMany and delete_clips) |
| delete one already-deleted clip forever (same as clips.purge and purge_clip) |
| print a clip's rendered captions as an SRT or VTT file (same as clips.captions and get_clip_captions) |
| print a project's transcript as an SRT or VTT file (same as projects.transcriptFile and get_project_transcript_file) |
| use a subtitle file as the transcript instead of transcribing (same as projects.importTranscript and import_transcript) |
| rename a project or change its settings without re-running anything (same as projects.update and update_project); values are JSON or text |
| hide or keep text burned into the source and re-render finished clips (same as projects.setSourceText and set_project_source_text) |
| change the caption/hook style of the whole project, clearing per-clip overrides and re-rendering (same as projects.updateStyle and update_project_style); values are JSON or text |
| start a project from a link for an account (the given user, else the only account); same as projects.create and create_project; takes the same settings as update-project |
| resume a failed or stuck project from its furthest completed stage (same as the Retry button, projects.retry and retry_project) |
| pick clips again from the existing transcript, optionally with new selection settings; clips made or edited by hand stay (same as projects.reanalyze and reanalyze_project) |
| re-run refine steps on the existing transcript, then re-render (same as projects.refine and refine_project) |
| delete a project, restorable like a clip (same as projects.delete and delete_project); --forget-decisions forgets its decisions when it is purged |
| write the zip of rendered clips with YouTube / TikTok metadata; the same conditions as the Export button and export_project (every picked clip must belong to the project, at least one rendered) |
| add a clip from a time range of the source: exact keeps the bounds, ai picks the best moment inside them (same as clips.create and create_clip) |
| edit one clip; a change burned into the video re-renders it unless told not to (same as clips.update and update_clip) |
| remove deleted projects and replaced clips past DELETED_RETENTION_DAYS now |
| delete one already-deleted project forever (frees storage; minutes stay counted); its decisions stay in the decision log unless --forget-decisions |
| the account's decision log: what it accepted, rejected, cut and edited (Settings → Learning / list_decisions) |
| the decision log as JSON lines, for evals (export_decisions; harvest-decisions.ts, the decisions suite) |
| delete the account's decisions, or one project's (forget_decisions) |
| record the account's decisions or stop (Settings → Learning / set_learning) |
| write decisions still held in transcripts from before the log existed |
| the account's share links: target, state, expiry, last use (Settings → Share links / list_media_links) |
| a share link per clip (or one for the zip) that needs no sign-in (get_media_links); reuses the active one unless --ttl or --label |
| turn share links off now (revoke_media_link) |
| the account's webhook endpoints: masked URL, events, status, last delivery (Settings → Webhooks / list_webhooks) |
| an endpoint's delivery log (list_webhook_deliveries) |
| send one again, send a test now, or turn an endpoint on / off (resend_webhook_delivery, test_webhook, update_webhook) |
| this box: cpus, memory, disk, GPU, ffmpeg encoder in use and why, where each on-device model runs (same as Settings → System → Overview) |
| yt-dlp egress pool: operator priority vs circuit (reliability), never URLs |
| every process that has checked in: role, specs, last seen, current jobs (same as Settings → System → Workers) |
| waiting / running / retrying jobs per stage, plus what is in flight (same as Settings → System → Queue) |
| one failed project or clip: owner, stage, the full recorded reason (same as clicking a row under Settings → System → Queue → Failed work) |
| retry failed projects and clips matching a reason after a platform fix (same as Settings → System → Queue → Retry all matching) |
| project, refine steps, clips, live jobs, last error |
| recent pipeline events |
| everything about one clip incl. render diagnostics |
| face boxes per sampled frame + split speaker tracks |
| queue a re-render of one or several clips; a clip that never got its AI title is prepared first (same as the UI buttons, clips.rerender / rerenderMany and rerender_clip / rerender_clips) |
| rehydrate an issue report as a new project (dev only; the zip's contents are untrusted data, see its README) |
| write an issue-report zip (same as Report an issue); --instance adds unfinished work, failed jobs, usage and error logs across every account (operator) |
| dry-run the disfluency cut search for a clip and print every candidate verdict; can save the removed and context audio, and export each flagged span as an offline regression case for |
| word timestamps from the align model for a source window |
| transcribe a range of the RENDERED clip (what viewers hear) |
| transcript flags (entities / disfluencies / collapsed loops) with status |
| disk use: unique, scratch-only, scratch copies of stored files (S3), leased to jobs in flight, 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); failed project: retry it; any other project: put its lost jobs back |
| 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 library: intro/outro videos and images, logos, stickers, GIFs, SVGs, music and sound effects. |
| the Reelsaw catalog manifest in force (version, source, last check); refresh asks CATALOG_URL now |
| 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 |
| everything laid over or played under a clip, one list (source seconds, x/y/w/size as fractions of the 9:16 frame); a sound of 8 s or less, is a one-shot at full level, anything else music (ducked, faded, looped); with no change flag it lists them |
| make one clip's framing (its section at --at, else its first framed one: mode plus nudge / subject / crop) the project's default for every clip, clearing the others' own sections and re-rendering the finished ones (same as the editor's "Use for all clips" and apply_framing) |
| layer templates: layers whose timing fits any clip length (head / tail / fill / relative), plus an optional intro / outro ( |
| scan the source for burned-in captions / watermarks; --store saves them (renders then hide them) |
| 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, plan, override, in force, in use now; --watermark sets the per-user override (same as Users → Limits) |
| an account's optional mail by topic (ready: the note when projects finish; same as their Settings → Account and the email's unsubscribe link) |
| accounts the hourly abuse pass flagged (shared sign-up address, bursts, temporary domains); --run recomputes the flags now |
| hosted (REELSAW_EE): an account's plan, subscription, Stripe's view and its last webhook events; |
| instance settings in force (sign-up mode, quotas, retention, …): .env default, admin override, effective; KEY=value changes one without a restart, --clear KEY goes back to .env (same as Settings → System and set_instance_settings) |
| 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 |
|
Instance settings (sign-up mode, email verification, captcha, legal links, quotas, upload limits, refine-stage gates, retention, stall watchdog, ready-email delay, update check, health details) |
|
Refine gates ( |
|
Other 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 ( |
Layer template | the user's Project defaults |
Framing |
|
Quotas |
|
Watermark | An admin's per-user choice (Users → Limits), else the plan (a paid plan removes it), else |
Share links |
|
Webhooks |
|
Learning (the decision log) | On for every account; the user's Settings → Learning switch (or |
Two things to know:
An env / instance refine gate wins.
DISFLUENCY_REMOVAL=false(or the matching Pipeline setting) skips filler removal for everyone even when a project asks for it; the new-project form disables that toggle and says so.TRANSCRIPT_BIAS=falsestill silently ignores vocabulary hints (.envonly). 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. Some steps depend on the process's role: a process with RUN_WORKERS=false only warns when free disk is under MIN_FREE_DISK_MB (so a full disk cannot lock out the admin UI that frees it) and skips the face, text and voice detectors; a process with RUN_HTTP=false skips the mail server check. 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
Every image is built by the release workflow with an SBOM and SLSA provenance attached, and a GitHub artifact attestation for its digest. Verify what you are about to run:
gh attestation verify oci://ghcr.io/osbytes/reelsaw:latest --owner osbytes
docker buildx imagetools inspect ghcr.io/osbytes/reelsaw:latest --format '{{ json .SBOM }}' | head -c 400Users 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. Admins can tick Instance-wide diagnostics to include
unfinished work, failed jobs, usage and error logs across every account — for queue, disk or
machine problems, not only their own projects. 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
Health. GET /api/health is a readiness check, not a ping. It answers 200 {"ok": true, "checks": {…}} when
Postgres answers, the event listener is connected, the job queue is started and (in a process that runs workers) its
worker heartbeat is fresh; each check has a 2 s timeout. Otherwise it answers 503 {"ok": false, "checks": {…}} with a
short reason per failing check (db, events, queue, workers), and the log has the detail. The Docker
HEALTHCHECK and any load balancer pointed at it restart or drain a process that is up but cannot work.
Errors and product analytics (optional). SENTRY_DSN turns on Sentry: the server reports
every error or fatal log line that carries an error, tagged with the line's ids (5xx
responses, unexpected MCP tool errors, a job's final failed attempt, a job the reconciler gave up
on, failed emails and billing syncs, process crashes; a retry still to come is a warning); the web app reports
render errors and unhandled rejections, but not the 4xx refusals it already shows the person. The
worker heartbeat (heartbeat-<WORKER_ID or role>), the reconciler and the daily billing reconcile
check in as Sentry cron monitors, so a stopped worker or a loop that no longer runs raises an alert.
SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE (default 0) keeps a fully masked replay of the moments before
a browser error. POSTHOG_KEY (and POSTHOG_HOST, EU cloud or self-hosted) turns on PostHog: the
server sends sign-ups, approvals, email verification, project created / done / failed / cancelled,
clip done / failed, jobs a person asked for, quota refusals, clip downloads and exports, MCP tool
calls (tool, outcome, client name), and billing and abuse-flag events, each with the surface it came
through (web, api, mcp, cli); the web app sends page views and a handful of product events
(lib/telemetry.ts). Event properties are ids, counts, durations and names, never a title, an
error message or other free text; people are identified by user id, role and plan only, with no
autocapture and no session recording. Both are off unless set, the browser gets the public keys
from system.status, and the SDK chunks are only requested when on. Prompts, transcripts and media
never go through either (apps/server/src/telemetry.ts). Release images upload their source maps to
Sentry when the release workflow has SENTRY_AUTH_TOKEN (.github/workflows/release.yml); no map
ships in the image.
OTEL_ENABLED=true
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318 # OTLP/HTTP; traces + metrics
OTEL_SERVICE_NAME=reelsawSentry's OTLP endpoint takes traces and logs (…/integration/otlp, plus OTEL_EXPORTER_OTLP_HEADERS). Each pino line that passes its level is exported to /v1/logs, with the active trace id attached; prompt, transcript and address fields stay in the local log. Sentry does not ingest OTLP metrics. With SENTRY_DSN set and OTEL_METRICS_ENABLED left on, the server sends Node runtime gauges (memory, CPU, event loop) and the metrics below through the DSN instead. Set OTEL_METRICS_ENABLED=false to keep traces and logs and drop those metrics.
Metrics. Durations are seconds. Attributes are bounded sets (stage, proxy id, model, outcome), never a project, clip or user id. Work grows with the video, so the stage, download and transcription numbers each come with a realtime factor: wall seconds per second of media (0.25 = a 1-hour video takes 15 minutes), comparable across a 30-second clip and a 2-hour talk.
Metric | Unit | Attributes | What it answers |
| s |
| How long each stage job takes and how often it fails |
| s |
| Source length per finished job (clip length for prepare and render) |
| 1 |
| Stage seconds per second of media; render excludes the wait for a slot |
| s |
| One link download through the pool, fallbacks and waits included |
| 1 |
| Download seconds per second of video, by the proxy that served it |
| By/s |
| Source bytes per second, by proxy |
| {download} |
| Links downloaded under a minutes limit before their length was known, so the limit was checked only on the file |
| {attempt} |
| Which candidate was tried and why it failed: |
| s |
| Wall time of one yt-dlp process through one candidate |
| {change} |
| Circuit opens (cooling), half-opens and closes |
| gauge |
| Circuit closed (1) or cooling (0), running downloads, last-20 success rate |
| s, s, 1 |
| Transcription time, audio per call, seconds per audio second |
| s |
| Language model latency per pipeline step |
| {token} |
| Tokens per call |
| USD |
| Provider-reported cost (AI Gateway) |
| gauge |
| Renders running in a worker and the limit CPU and memory allow |
| gauge |
| Jobs a worker process is running |
| s |
| Every |
Over OTLP, the auto-instrumentation adds http.server.request.duration, and pg-boss adds messaging.process.duration and pgboss.queue.jobs (backlog by queue and state). A proxy dashboard: reelsaw.ytdlp.download.realtime_factor p50/p95 by proxy, reelsaw.ytdlp.attempts rate by proxy and outcome, and reelsaw.ytdlp.proxy.healthy by proxy.
Spans: inbound HTTP named by route (POST /api/trpc/projects.create; /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. A client span with no parent (an S3 read or a query no request or job is around, such as queue polling) is not recorded unless OTEL_TRACES_SAMPLER is set.
The browser exports its own spans as reelsaw-web (page load, navigation, fetch, and live subscriptions; not clicks) and sends traceparent on API calls, including the subscription stream, so a click and the server work it starts are one trace. OTEL_TRACES_SAMPLE_RATE (default 1) is the fraction kept, on the browser and the server together. The Sentry browser SDK does not trace; those spans would be a second copy.
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 (over MCP: list_transcript_flags, review_transcript_flags, add_transcript_correction, add_transcript_cut). 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, asr-loops, scenes, pauses, alignment, speakers, overlays, cuts, transcription, disfluency, decisions, 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 still open:
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.
Direct publishing to YouTube Shorts / TikTok / Instagram.
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. The hosted service's additions (billing)
live in apps/server/src/ee and apps/web/src/ee under the Reelsaw Enterprise License and load
only with REELSAW_EE=true; see LICENSING.md. Contributions need a DCO sign-off
(git commit -s), see CONTRIBUTING.md.
Copyright (C) 2026 osbytes
Available Tools
84 toolsadd_assetAdd library assetA
Add from exactly one source: a public url or an uploadId (video, image, GIF, SVG or sound) becomes one of your library uploads; a search_assets catalog / provider hit (provider + externalId) materializes one instance-shared copy (checksum verified, license recorded; not listed in your library). Returns { id, name, kind, mime, durationSec, duplicate, restored, owner } (the same file twice returns the existing item). setDefault on an upload makes it your default intro/outro for NEW projects only.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | http(s) link to a video (MP4/MOV/WebM), image (PNG/JPG/WebP/GIF/SVG) or sound (MP3/M4A/AAC/WAV/OGG/FLAC); the server downloads it into your library (max 50 MB, 60 s) | |
| name | No | Library name (url or uploadId; default: the file name). update_asset changes it later | |
| tags | No | Search tags (lowercase words; max 20) | |
| color | No | iconify hits only: icon color as hex, e.g. #ffffff (default white) | |
| provider | No | A search_assets hit's provider (catalog or an enabled provider), together with externalId; materializes the instance-shared file instead of adding an upload | |
| uploadId | No | An existing upload id (from POST /api/upload) instead of a url | |
| externalId | No | A search_assets hit's externalId, together with provider | |
| setDefault | No | Also make it your default intro or outro for new projects | |
| imageSeconds | No | How long a still image shows as an intro/outro (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 most of it: idempotency ('the same file twice returns the existing item'), checksum verification and license recording for provider hits, the fact that provider materializations are not listed in your library, and the forward-only effect of setDefault. It omits permission/auth requirements and any rate-limit or cost context for provider materialization.
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, front-loaded with the constraint that matters most (exactly one source) and ending with the caveat about setDefault. The dense parentheticals are efficient rather than redundant, though the packed first sentence takes effort to parse.
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?
Nine parameters with 100% schema coverage and no output schema, and the description still specifies the return shape ({ id, name, kind, mime, durationSec, duplicate, restored, owner }) plus the meaning of the duplicate/restored flags via the idempotency note. An agent has everything needed to call 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 coverage is 100%, so baseline is 3, but the description adds semantics the schema cannot express: that url, uploadId, and provider+externalId are mutually exclusive source selectors, and that setDefault applies only to future projects. That is genuine value beyond the field-level docs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence gives a specific verb (add) and enumerates the three mutually exclusive source modes that produce distinct outcomes: an upload in your library, or an instance-shared copy materialized from a search_assets hit. It names the sibling tools (search_assets, update_asset) that bracket this operation, so an agent can place it 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?
'Add from exactly one source' states the mutual-exclusion rule and then maps each available input (public url, uploadId, provider+externalId) to its use case, which is real routing guidance. It also scopes setDefault to NEW projects only. It stops short of saying when not to use this tool (e.g. restore_asset for previously deleted items), so it is not fully exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
add_transcript_correctionCorrect transcript wordsA
Make captions show "text" instead of the words spoken between startSec and endSec (a misheard name, say); the span must cover whole words. Returns { ok, flagId, rerendered, hint }. Undo it by passing the flagId to review_transcript_flags with status rejected.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| text | Yes | What the captions should say for that span | |
| endSec | Yes | End of the words to correct, seconds | |
| rerender | No | Re-render finished clips whose captions overlap the span (default true) | |
| startSec | Yes | Start of the words to correct, seconds from the start of the source video |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full weight and does well: it discloses the return shape { ok, flagId, rerendered, hint }, which implies a review flag is created, and explains how to reverse the change. Missing are permission requirements, whether the source transcript or existing renders are otherwise altered, and what `hint` means.
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 clauses: the effect first, the constraint second, the return and undo last. Nothing is padded and the most important information 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?
For a mutation tool with no annotations and no output schema, the description supplies both the response fields and the reversal path, which is exactly the gap structured data leaves. It could go one step further on permission or review-workflow impact, but an agent can 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 high; the description still adds meaning by tying startSec/endSec to "the words spoken" and clarifying that text is what the captions should read, reinforcing the whole-word constraint. No redundant restatement.
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 the concrete effect (captions show "text" instead of the spoken words) plus the exact span parameters, so it is unmistakable what resource is mutated. The contrast with review_transcript_flags (undo path) and add_transcript_cut clarifies its niche.
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 motivating case ("a misheard name, say"), a hard precondition ("the span must cover whole words"), and an explicit undo route via review_transcript_flags with status rejected. It stops short of saying when to prefer add_transcript_cut or list/flags-review workflows instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
add_transcript_cutCut transcript wordsA
Remove the words spoken between startSec and endSec from the transcript, so captions and the rendered video skip them; the span must cover whole words. Returns { ok, flagId, rerendered, hint }. Undo it by passing the flagId to review_transcript_flags with status rejected.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| endSec | Yes | End of the words to cut, seconds | |
| rerender | No | Re-render finished clips whose captions overlap the span (default true) | |
| startSec | Yes | Start of the words to cut, seconds from the start of the source video |
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 that the operation mutates the transcript, affects captions and rendered video, requires whole-word spans, returns specific fields, and can be reverted via review_transcript_flags. It omits failure behavior if the span does not cover whole words and any permission/auth context.
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, front-loaded with the action and effect, followed by return shape and undo guidance. Every sentence adds useful information with no repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no annotations and no output schema, the description is largely complete: it explains the effect, return fields, and reversal path. The main gap is what happens when the span fails the whole-word requirement and whether there are other prerequisites.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds a meaningful constraint beyond the schema by stating that startSec and endSec must cover whole words, which affects how the agent should choose those values.
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 the words spoken between startSec and endSec from the transcript', and immediately explains the downstream effect on captions and rendered video. It also distinguishes its undo path from review_transcript_flags, making the operation identifiable against transcript-related siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit reversal route: 'Undo it by passing the flagId to review_transcript_flags with status rejected.' It also states the constraint that the span must cover whole words. It does not, however, compare itself to add_transcript_correction or say when to cut versus correct.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
apply_framingApply framing to the projectADestructive
Make one clip's framing the whole project's, for a recording whose layout never changes (a slide deck with a webcam tile, a fixed camera): the clip's section at at (else its first framed section) gives the mode and its nudge / subject / crop, which become the project's reframe and reframeAdjust; every clip's own sections are cleared (unless keepOverrides) and the finished clips re-render. New clips get it too. Returns { reframe, adjust, cleared, rerendered }.
| Name | Required | Description | Default |
|---|---|---|---|
| at | No | Seconds from the start of the source: which section of the clip to copy (default: its first section that is not plain automatic) | |
| clipId | Yes | Clip whose framing to copy (from get_project or search_clips) | |
| rerender | No | Re-render the finished clips now (default true) | |
| keepOverrides | No | Leave other clips' own sections in place; they still win over the project's framing (default false: clear them) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond destructiveHint=true, it discloses exactly what gets destroyed: every clip's own sections are cleared unless keepOverrides, and finished clips are re-rendered. It also notes forward behavior ("New clips get it too") and the response shape, which annotations alone would never convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One front-loaded sentence that leads with the action and the applicability constraint, followed by the return shape. It is dense with parentheticals and nested clauses, but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive mutation with no output schema, it covers the source of truth, the clear/keep behavior, the re-render default, the effect on future clips, and the returned fields. An agent has everything needed to call it correctly and know the consequences.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description earns above that by explaining the semantics of `at` (the clip's section at that point, else its first framed section) and how keepOverrides interacts with the project framing (other clips' sections "still win"). It adds meaning rather than restating field descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: copy one clip's framing (mode, nudge, subject, crop) and make it the project's reframe/reframeAdjust. It also scopes the operation to recordings with a fixed layout, which separates it from per-clip tools like rerender_clip or update_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 concrete when-to-use condition ("a recording whose layout never changes (a slide deck with a webcam tile, a fixed camera)"), which implicitly excludes variable-layout projects. It does not name an alternative tool for the case where layouts vary, so the routing 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.
apply_layer_templateApply layer template to clipsADestructive
Write a template onto clips of one project (up to 200 clipIds, or all): its layers fitted to each clip's length, and the intro / outro it sets as each clip's own. Not linked afterwards. mode replace (default) swaps the clips' layers, add keeps them and adds. rerender true re-renders finished clips now, else the next render shows them. update_project settings.layerTemplateId only affects clips created later. Returns { updated, rerendered, skipped: [{ clipId, reason }], layersSkipped, bumpers: slots set }
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | "replace" (default) = the template becomes the clip's layers; "add" = its layers join the ones the clip already has | replace |
| clipIds | No | Clip ids of that project (get_project), 1-200; omitted = every clip of the project | |
| rerender | No | true = re-render the affected finished clips now; false = the layers show on their next render | |
| projectId | Yes | Project the clips belong to (list_projects) | |
| templateId | Yes | Layer template id (list_layer_templates) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations supply only destructiveHint=true; the description earns credit by disclosing that replace swaps (destroys) existing clip layers, that templates are not linked afterwards, that rerender controls whether finished clips update now or later, and what the response contains including skipped clipIds with reasons. It does not mention permission requirements or whether the call is synchronous/queued, which for a destructive batch mutation would be useful.
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 core action and scope, then parameters, then return shape — a sensible order with no filler sentences. The prose is over-compressed in places ("the intro / outro it sets as each clip's own", "bumpers: slots set"), which costs a little readability but not much length.
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 summarizes the return payload (updated, rerendered, skipped with reasons, layersSkipped, bumpers), and it covers every parameter's behavioral consequence plus the non-linkage semantics. Remaining gaps are peripheral: sync vs async execution, partial-failure semantics beyond the skipped list, and permission prerequisites for a destructive batch write.
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 mode, clipIds, rerender, projectId and templateId are already fully documented in the schema, and the description largely restates them. The only genuinely additive semantics is the caveat about layerTemplateId on update_project affecting only later-created clips. Baseline 3 applies 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?
"Write a template onto clips of one project" names a specific verb (write/apply) and resource (layer template → clips), and adds scope (up to 200 clipIds, or all). "Not linked afterwards" separates it from the template-management siblings (save_layer_template, update_layer_template) that would otherwise look similar. An agent can distinguish this from every sibling 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 gives the operative decision rules: mode replace vs add, rerender true/false, and clipIds omitted = every clip. The note that "update_project settings.layerTemplateId only affects clips created later" implicitly tells the agent this is the tool for retroactive application, which is a strong when-to-use signal. It stops short of explicitly naming an alternative tool for the settings-only path.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
asset_usageWhere a library asset is usedARead-only
Where a library item is used: as intro, outro, overlay or music on projects and clips (replaced clips left out), and in layer templates. Returns { projects: [{ id, title, slots, clips: [{ id, index, title, slots, via, overlays, music }] }], templates: [{ id, name, layers }] }. A deleted asset's layer is skipped when a template is applied. Check before deleting one.
| Name | Required | Description | Default |
|---|---|---|---|
| assetId | Yes | Library asset id (from search_assets) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond readOnlyHint=true by disclosing non-obvious semantics: replaced clips are excluded, and a deleted asset's layer is skipped when a template is applied. These behavioral details materially affect how an agent interprets results before a destructive action.
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 core purpose, followed by the return shape and then the actionable caveat. The inline return-shape block is dense but justified since no output schema exists; nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description supplies the full response shape (projects with nested clips/slots/via/overlays/music, and templates with layers) and the caveats that affect interpretation. An agent has everything needed to call it and read the result correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single parameter, and the schema already documents it fully (id from search_assets), so baseline applies. The description adds no syntax, format, or sourcing guidance beyond what the schema states.
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 resource (a library item) and precisely what is reported: its use as intro, outro, overlay or music on projects and clips, plus layer templates. This is clearly distinguishable from siblings like get_clip or search_assets, which retrieve content rather than reverse-lookup usage.
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 instruction 'Check before deleting one' gives an explicit trigger for calling this tool, implicitly routing agents here before delete_asset/purge_asset. It does not explicitly name those siblings or state when-not to use it, so it stops short of a full routing rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
billing_checkout_urlCheckout URLA
Hosted instances: a Stripe Checkout URL for a plan (or, when the account already pays, the Billing Portal page that confirms the plan change). Returns { url, kind: "checkout" | "change" }; a person must open it in a browser, an agent cannot pay. Plans and intervals come from get_billing.
| Name | Required | Description | Default |
|---|---|---|---|
| plan | Yes | Plan name from get_billing (e.g. creator, pro) | |
| interval | No | Billing interval: month (default) or year | month |
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 return shape and the two possible `kind` outcomes, and warns that payment requires a human in a browser. It never says whether calling it creates a Stripe session as a side effect or is idempotent, which matters for a tool that provisions checkout state.
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 clauses with no filler, front-loaded with the 'Hosted instances' scope qualifier. The nested parenthetical and 'Returns { url, kind: ... }' shorthand make it slightly harder to parse than it needs to be, but nothing is wasted.
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 naming the returned fields and the `kind` discriminator. Parameters, hosting scope, human-in-the-loop requirement, and the alternate return path are all covered, so an agent knows what it will get and what to do with 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 coverage is 100% and the schema already documents both `plan` (from get_billing) and `interval` (month/year with default), so the description repeats rather than extends that. It adds nothing about format constraints, casing, or invalid-plan behavior 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?
States exactly what is returned: a Stripe Checkout URL for a plan, or the Billing Portal page when the account already pays. It explicitly distinguishes itself from get_billing, which supplies the plan/interval values rather than the URL.
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?
Clear context: 'Plans and intervals come from get_billing' routes the agent to the sibling that supplies inputs, and 'a person must open it in a browser, an agent cannot pay' sets a hard usage constraint. The 'Hosted instances' prefix implies self-hosted installs are unsupported, but that exclusion is left implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
billing_portal_urlBilling portal URLA
Hosted instances: a Stripe Billing Portal URL to see invoices, change the card or cancel at period end. Returns { url }; a person must open it in a browser. On a self-hosted Reelsaw this answers that billing is not enabled.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
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 that the call is non-mutating (returns a URL rather than acting), that a human must open it in a browser, and that self-hosted deployments get a 'billing not enabled' outcome instead of a URL. It omits whether the URL is user-scoped, expiring, or requires admin auth, which leaves some behavioral gaps.
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: what it returns and what it is for, the human-in-the-loop requirement, and the self-hosted fallback. Nothing is wasted and the primary 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?
For a zero-parameter tool with no output schema, the description explains the return payload ({ url }) and the human browser step, plus the self-hosted degenerate case. Lifetime/expiry of the URL and any auth prerequisites are the only notable omissions.
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 per the baseline this scores 4. The description adds no parameter information but none is needed.
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 artifact (a Stripe Billing Portal URL) and its concrete uses (see invoices, change card, cancel at period end), which clearly separates it from a checkout URL or a billing status read. It does not name the nearest siblings (billing_checkout_url, get_billing) explicitly, so the differentiation is inferred rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear usage condition split by deployment: on hosted instances it is the way to manage billing, while on a self-hosted Reelsaw it simply reports that billing is not enabled. There is no explicit routing to alternatives, but the hosted/self-hosted framing supplies usable context for when the tool applies.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_for_updateCheck for updateARead-only
Admins only: is a newer Reelsaw published? Returns { current, latest: { version, url, publishedAt }, available, checkedAt, error, upgrade: { command, note, docsUrl } }; available is null when the running build is not a release (from source). The server checks every few hours; refresh: true asks GitHub again now.
| Name | Required | Description | Default |
|---|---|---|---|
| refresh | No | true = ask GitHub now instead of returning the last answer (at most once a minute) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, and the description adds substantial behavior: the full return shape, the fact that available is null for non-release/source builds, the cached polling cadence, and what refresh does. There is no contradiction with the read-only 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?
Two dense sentences with no wasted framing. The admin restriction is front-loaded, and the return shape is stated compactly because no output schema exists 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?
For a one-parameter, read-only diagnostic tool with no output schema, the description covers audience, return values, the key edge case, caching behavior, and refresh semantics. Nothing important for correct invocation appears to be missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and already documents refresh, default false, and the once-per-minute limit. The description adds useful context by explaining why refresh exists: the server otherwise returns the last cached check from its every-few-hours polling.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: checking whether a newer Reelsaw release is published. It also names the admin-only audience and distinguishes this operational/update check from the many project, clip, and bumper tools in the sibling list.
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 clearly says this is for admins and explains that the server normally checks every few hours, while refresh: true forces an immediate GitHub check. It does not name alternatives or explicit when-not-to-use conditions, but the intended context is clear.
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 summary { id, status: "preparing", queued: "prepare", hint }; preparation (title, hook, scores) is queued and the render follows by itself (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 whole burden and does so well: it discloses that the call is asynchronous, that preparation is queued, that rendering follows automatically and takes about a minute, and that the caller must poll get_clip. It does not cover failure modes or what happens if the range exceeds the stated 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?
Every sentence earns its place and the core purpose comes first, but the single dense paragraph with stacked parentheticals ("(title, hook, scores)", "(about a minute)") makes it heavier to parse than necessary. No wasted claims, just tight packing.
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, and the description compensates by giving the exact return shape { id, status, queued, hint } plus the follow-up workflow via get_clip. Combined with the mode limits and the transcript prerequisite, an agent has everything needed to call this correctly on the first try.
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 constraints the schema lacks: a 3 s–10 min bound in exact mode and a ≥8 s minimum in ai mode. It does not add anything for projectId, startSec, or endSec beyond what the schema already states.
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 ("Add a clip from a time range of the source") and immediately adds the prerequisite that the source needs a transcript. It distinguishes itself from update_clip and get_clip by name within the same paragraph.
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?
Spells out the two operating modes with their selection criteria (exact keeps your bounds, ai lets the model pick the best moment) and names the alternative for mutation ("To change an existing clip use update_clip instead"). The transcript prerequisite further tells the agent when this call will not work.
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 (anything yt-dlp fetches) or a file you uploaded: POST /api/upload with the file as the body, header x-filename and your API key as Authorization: Bearer, then pass the uploadId it returns. 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) | |
| metadata | No | Your own key/value strings (≤20 keys, 1 KB), returned by get_project and sent in every webhook for this project, e.g. { runId: "n8n-123" } | |
| 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, name fixes and the on-screen text scan on, filler removal off). Set refineDisfluency / disfluencyLlm true to opt into filler removal, refineEntities / refineScenes false to skip those steps (instance Pipeline gates must be on). | |
| uploadId | No | Id returned by POST /api/upload (the file body, x-filename header, API key as Bearer); give this or sourceUrl | |
| sourceUrl | No | http(s) URL of the video; give this or uploadId | |
| introAssetId | No | Library asset id (search_assets with source library) 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 exist, so the description carries the burden and does well: it discloses the asynchronous pipeline (download, transcribe, pick, render) running for minutes, the immediate return shape with status 'queued', and the required follow-up call. It could be stronger by mentioning error conditions or whether creation consumes quota, but the core behavioral profile is clearly disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The opening action and source options are front-loaded, and the sentence is dense with useful detail. However, it is a single long run-on sentence that could be split for easier scanning.
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 9-parameter, nested, no-output-schema tool, the description provides the crucial return shape and async follow-up guidance, which compensates for the missing output schema. It does not cover error behavior or quota implications, but nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description reiterates the uploadId flow and intro/outro default semantics, but those are already documented in the schema; it adds little parameter-level meaning beyond what the schema provides.
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 (start clipping) and resource (project), plus the two source modes it accepts. It also names the follow-up sibling wait_for_project, so an agent can distinguish it from read/update siblings 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 says how to start (URL or uploaded file via POST /api/upload with uploadId) and what to do after (follow with wait_for_project(id)). It also states the intro/outro default behavior versus supplying introAssetId/outroAssetId, so the invocation path is fully prescribed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_webhookCreate webhookA
Subscribe a URL to events: project.created, project.done (with every clip, share links and the zip), project.failed, clip.done (also re-renders), clip.failed. This is how a Zapier or Make app subscribes (delete_webhook unsubscribes). Returns { endpoint, secret }: the whsec_ signing secret is shown only here; verify deliveries with any Standard Webhooks library. The URL must be public https unless the admin allows private networks.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Where to POST (https) | |
| events | Yes | Events to send | |
| description | No | Your label, e.g. "n8n clips workflow" |
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: it discloses the return shape { endpoint, secret }, the one-time-only nature of the whsec_ secret (an irreversible behavior), how to verify deliveries, and the public-https / private-network constraint. These are exactly the facts an agent needs before firing a mutation it cannot undo.
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 dense sentences with zero filler, front-loaded with the verb and the event list, then the return contract, then the URL constraint. The event enumeration is long but is load-bearing information, not 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, yet the description documents the response object and the secret's one-time visibility, covers the https requirement, and names the verification path. Nothing essential for a correct first call 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; the description goes beyond the enum names by explaining what each event actually delivers ('project.done (with every clip, share links and the zip)', 'clip.done (also re-renders)'). It does not add anything for the optional 'description' label, but the schema already covers that adequately.
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 ('Subscribe a URL to events') and enumerates the exact event types it accepts. It also names the sibling it is not ('delete_webhook unsubscribes'), so an agent can place it in the webhook lifecycle 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?
'This is how a Zapier or Make app subscribes' plus the parenthetical pointing at delete_webhook as the inverse gives clear context and one named alternative. It does not explicitly contrast with update_webhook or rotate_webhook_secret, which are the closest ambiguous siblings for an agent that already has a webhook registered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_assetDelete library assetADestructive
Delete one of your uploads: it leaves the library and your defaults and goes to Deleted. Projects and clips already using it keep rendering with it. Undo with restore_asset (list_deleted says how long it is kept); check asset_usage first. Returns { ok }.
| Name | Required | Description | Default |
|---|---|---|---|
| assetId | Yes | Library asset id (from search_assets) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With only destructiveHint=true available, the description carries the burden well: it discloses soft-delete semantics (moves to Deleted), the retention window is discoverable via list_deleted, the key non-obvious side effect that existing projects/clips keep rendering with the asset, and the return shape { ok }.
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, each earning its place: what it does, what survives, how to undo/verify, and what comes back. The behavioral constraint is front-loaded ahead of the recovery advice.
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 mutation with no output schema, the description covers effect, reversibility, retention, downstream render impact, and the return value. Nothing an agent needs in order to call this safely 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?
A single required parameter with 100% schema description coverage (including its provenance, 'from search_assets'), so the schema already does the work. The description adds only an indirect hint that the asset must be one of the caller's own uploads, not syntax or sourcing detail 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?
States a specific verb+resource ('Delete one of your uploads') and immediately clarifies the scope: it leaves the library and defaults but goes to 'Deleted' rather than being destroyed. This implicitly separates it from purge_asset while explicitly naming restore_asset and asset_usage, so an agent can place it among the delete/purge siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives real procedural guidance: 'check asset_usage first' establishes a precondition, and 'Undo with restore_asset (list_deleted says how long it is kept)' points to the recovery path. What's missing is an explicit exclusion — it never says to use purge_asset when permanent removal is intended.
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 a live project; a render in progress stops. It shows up on Deleted (list_deleted). Reversible: restore_clip brings it back for DELETED_RETENTION_DAYS (7 days by default). Storage still counts until purge_clip. For several clips of one project use delete_clips. Returns { changed, stoppedRender (a render in flight was stopped), renderQueued: false, restorable, storedBytes }.
| 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 destructiveHint=true and idempotentHint=true, but the description adds substantial behavior the annotations do not: a render in progress stops, the item becomes visible in Deleted, deletion is reversible for DELETED_RETENTION_DAYS (7 days default), and storage still counts until purge_clip. It also describes the return payload fields, which is especially valuable because no output schema exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense and front-loaded: purpose first, then lifecycle consequences, then the bulk alternative, then return fields. Every sentence carries operational information and there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive single-item delete with no output schema, the description covers the full operational picture: what happens to an in-flight render, where the item goes, how long it is restorable, when storage is actually freed, the relevant sibling tools, and the return object fields. 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% and the single id parameter is fully documented in the schema ('Clip id (from get_project or search_clips)'). The description does not add any further meaning about the id parameter, so the baseline of 3 for full schema coverage is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Delete one clip of a live project') and immediately distinguishes scope from the bulk sibling ('For several clips of one project use delete_clips'). An agent can tell exactly what this tool does and how it differs from delete_clips, purge_clip, and restore_clip.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly names the alternative for bulk deletion ('use delete_clips') and explains the lifecycle context: the clip appears in list_deleted, is restorable via restore_clip for the retention period, and only stops counting toward storage after purge_clip. That gives clear when-to-use and when-to-use-something-else guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_clipsDelete clipsADestructiveIdempotent
Delete several clips of one live project in one step (the selection bar's Delete); renders in progress stop. Each shows up on Deleted (list_deleted) and restore_clip brings it back for DELETED_RETENTION_DAYS. Already-deleted ids are skipped. Storage still counts until purge_clip. Returns { deleted, skipped, stoppedRenders, renderQueued: false, restorable, storedBytes }.
| 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 past destructiveHint/idempotentHint: in-progress renders are stopped, deletions land on Deleted and are restorable for DELETED_RETENTION_DAYS, skipped ids are ignored (explaining the idempotency claim), and storage continues to be billed until purge_clip. It also documents the response payload, which no output schema provides.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and scope, then lifecycle, then return shape; no filler sentences. The trailing return-field enumeration is dense but pays for itself since there is no output 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?
Covers action, side effects, recovery window, purge relationship, retry semantics and the full return object, compensating for the absent output schema. Nothing needed 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 coverage is 100%, so baseline is 3, but the description adds real semantics: all clipIds must belong to a single live project, and ids already in the deleted state are silently skipped rather than erroring — behavior an agent needs to interpret results.
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 with scope: 'Delete several clips of one live project in one step', and disambiguates from the singular sibling by calling out the batch/selection-bar semantics. An agent can distinguish it from delete_clip, delete_project and delete_asset 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 the recovery path (list_deleted, restore_clip, DELETED_RETENTION_DAYS) and the true-removal alternative (purge_clip), and notes that already-deleted ids are skipped so retries are safe. It does not explicitly say 'use delete_clip for a single clip', so one routing decision is left implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_layer_templateDelete layer templateADestructiveIdempotent
Delete a template (it goes to Deleted) and drop it from your project defaults; clips that already got its layers keep them. Undo with restore_layer_template (list_deleted says how long it is kept). Returns { ok, clearedDefault } (it was your default and no longer is)
| Name | Required | Description | Default |
|---|---|---|---|
| templateId | Yes | Layer template id (list_layer_templates) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although annotations already declare destructiveHint=true and idempotentHint=true, the description adds substantial behavioral context: deletion is soft (goes to Deleted), it clears the template from project defaults, existing clips retain their layers, and the return value includes whether a default was cleared. It also names the restore path and the retention reference.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: the delete behavior, default-clearing effect, existing-clip behavior, undo path, retention reference, and return shape all appear in a few tight clauses with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter destructive tool with no output schema, the description covers the important effects: what happens to the template, project defaults, existing clips, how to undo, where retention is documented, and what the return value contains. 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 description coverage is 100% and the only parameter's schema already explains that it is a layer template id available via list_layer_templates. The description adds no additional parameter semantics beyond what the schema provides, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Delete a template') and immediately distinguishes this soft delete from permanent removal by saying it goes to Deleted and can be undone. An agent can tell this apart from purge_layer_template without inspecting either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear recovery guidance ('Undo with restore_layer_template') and points to list_deleted for retention duration. It does not explicitly compare against purge_layer_template, but the soft-delete semantics strongly imply when this tool is appropriate rather than permanent purge.
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). Storage still counts until purge_project (or the retention sweep) removes it for good; minutes already used stay counted. Returns { changed, restorable, storedBytes, forgetDecisions, message }.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| forgetDecisions | No | Forget what Reelsaw learned from it (its decision log entries) when it is deleted for good, by purge_project or the retention sweep; restoring it cancels that. Default false keeps them |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint and idempotentHint, but the description goes well beyond them: it discloses the soft-delete/retention model, that storage keeps counting until purge, that used minutes are not refunded, and the exact return payload. Nothing an agent needs to predict the consequences is missing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences, front-loaded with the destructive effect and scope, then reversibility window, then the residual-cost 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?
There is no output schema, and the description compensates by naming the returned fields ({ changed, restorable, storedBytes, forgetDecisions, message }). Combined with the retention and billing caveats, this is complete for a two-parameter destructive mutation.
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 both parameters (id, forgetDecisions) are documented there, so the schema does the heavy lifting. The description mentions forbidDecisions only as a return field and adds no syntax or constraint detail about either input parameter, 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 ("Delete one of your projects and all its clips") and immediately scopes the effect: work in progress stops and clips go with the project. It is clearly distinguishable from the sibling purge_project, which the description names as the permanent-removal path.
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: restore_project is the undo path within DELETED_RETENTION_DAYS (7 days default), and purge_project (or the retention sweep) is what actually frees the data. It also warns that minutes already used stay counted, which is decision-relevant before calling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_webhookDelete webhookADestructive
Remove a webhook (unsubscribe); nothing more is sent to it and its delivery log goes with it. Returns { ok, message }.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Webhook id (from list_webhooks) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, and the description goes beyond that by disclosing exactly what is destroyed: future deliveries stop and the delivery log is removed with it. It also names the return shape { ok, message }. It stops short of saying whether the deletion is reversible or what permission is required.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact clauses: the action with its consequence front-loaded, then the return contract. No filler and nothing repeated from the structured fields.
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 annotations and full schema coverage, this is nearly complete: mutation effect, collateral data loss, and return value are all covered. The remaining gap is whether the operation is permanent or has any restore path.
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, and the schema already documents it at 100% coverage ("Webhook id (from list_webhooks)"). The description adds nothing about the id's format or sourcing, 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 ("Remove a webhook") and immediately qualifies scope with "(unsubscribe)." It is unmistakably distinct from create_webhook, update_webhook, and list_webhooks, though it never names a sibling to route the agent.
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 when-to-use / when-not-to-use guidance and no alternative named (e.g., update_webhook to disable delivery without deleting). The word "unsubscribe" only implies the use case rather than stating conditions or prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_decisionsExport decisionsARead-only
A page of your decision log in export form, oldest first, for evals. Returns { items (one decision each, the same objects reelsaw decisions export writes as JSON lines), cases: { disfluency: [eval cases in eval/fixtures/disfluency/cases.json shape, split dev/heldout by project] }, nextCursor }. Pass nextCursor back until it is null.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | Only this kind of decision | |
| limit | No | Page size (1-1000, default 200) | |
| since | No | Only decisions made at or after this ISO time | |
| cursor | No | nextCursor from the previous page |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial behavioral detail beyond the readOnlyHint annotation: it describes the return shape, the oldest-first ordering, eval-case grouping, and cursor-based pagination. It does not mention auth or rate-limit behavior, but those are less critical for a read-only export.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and then efficiently covers return shape and pagination in a few dense but purposeful sentences. Every sentence contributes useful 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, the description carries the burden of explaining returns, and it does so by specifying items, cases, and nextCursor. It also covers ordering and pagination, making the definition complete for an agent 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. The description still adds meaningful semantics by explaining that the returned nextCursor is fed back into the cursor parameter until null, which clarifies the pagination contract beyond the schema field description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the resource and output mode: a paginated export of the decision log, ordered oldest first, intended for evals. It does not explicitly distinguish itself from the sibling list_decisions tool, so it is clear but misses full sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear usage context by saying the export is 'for evals' and explains the pagination loop ('Pass nextCursor back until it is null'). It does not state when not to use this tool or explicitly point to list_decisions for ordinary browsing.
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. Same conditions as the app's Export: the project must be live and at least one picked clip rendered, else the answer says why (not found, or nothing rendered yet). Returns { url, clips (rendered, in the zip), notRendered (picked but not finished, left out) }; 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?
Goes well beyond readOnlyHint: discloses that the returned link requires the same Authorization header as this server, that unrendered clips are silently excluded (notRendered), and what the error responses mean. That is exactly the kind of non-obvious auth/partial-result behavior an agent cannot infer from annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the outcome (a zip download link), then preconditions, then return shape. Dense but every clause carries information; only the nested parentheticals slightly slow parsing.
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 exact return shape ({ url, clips, notRendered }) and the mechanism for consuming the link (Authorization header). Combined with precondition and error behavior, an agent has everything needed to call and use this 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% and both parameters (id, clipIds with max 200 and rendered-only constraint) are already documented in the schema. The description mentions rendered vs picked clips but adds no syntax or format detail for the parameters themselves, 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 ('a download link for a zip of the project's rendered clips with YouTube/TikTok metadata'), which no sibling tool duplicates — delete_project, get_project, rerender_clips all do different things. An agent can immediately tell this is the export/download operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete preconditions ('the project must be live and at least one picked clip rendered') and explains failure outcomes. It does not name an alternative sibling for the case where nothing is rendered (e.g. rerender_clips), so it stops just short of explicit alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
forget_decisionsForget decisionsADestructiveIdempotent
Delete entries from your decision log so Reelsaw stops learning from them: one project's (projectId, live or already deleted forever) or, without projectId, all of them. Cannot be undone. Returns { forgotten, message }.
| Name | Required | Description | Default |
|---|---|---|---|
| projectId | No | Only this project's decisions; omitted = everything |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, so the safety profile is known. The description adds important context: deletions cannot be undone, affect learning behavior, and return { forgotten, message }.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short and front-loads the destructive operation and its learning consequence. The parenthetical phrase 'projectId, live or already deleted forever' is slightly awkward but overall the sentence is efficient.
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, it covers the essential scope, irreversibility, learning effect, and return shape. It could be more complete by relating explicitly to set_learning or non-destructive decision-log tools.
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 one optional projectId is already documented. The description reinforces that omitting projectId deletes everything, but adds little syntax or format detail 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?
States a specific verb and resource: delete entries from the decision log, with the consequence that Reelsaw stops learning from them. This clearly distinguishes it from sibling read/export tools like list_decisions and export_decisions.
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?
Explains project scoping well: projectId limits deletion to one project, omission deletes all. However, it gives no explicit guidance on when to use this versus related tools such as set_learning, list_decisions, or export_decisions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_billingBillingARead-only
Hosted instances: your plan and subscription, the billing period, the limits in force with where each comes from (instance, plan, an admin's override), what you have used this period, whether renders carry a watermark, and the plans on offer. Returns { enabled, plan, reason, subscription, period, limits, limitSource, usage, watermark, canManage, plans }. On a self-hosted Reelsaw this answers that billing is not enabled.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint=true annotation covers the safety profile, and the description adds real context beyond it: what the response contains, that limits carry a source (instance, plan, admin override), and that self-hosted deployments return an explicit 'not enabled' answer rather than an error. It stops short of stating permission requirements or what canManage implies for the caller.
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 hosted-instance scope, which is good, but the first sentence's prose list and the second sentence's return-key list largely restate each other (plan, subscription, period, limits, limitSource, usage, watermark, plans appear twice). The self-hosted note is the one non-redundant sentence and should not be buried at the end.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description carries the return-value burden and does so by enumerating the response keys plus the top-level enabled/reason/canManage fields. With zero parameters and a read-only annotation, the remaining gaps (auth requirements, what canManage gates) are minor for a status-reading tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes no parameters, so there is nothing for the description to disambiguate beyond confirming it acts on the current instance without arguments. Baseline applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource (billing/subscription for a hosted instance) and enumerates exactly what it reports: plan, billing period, effective limits with provenance, period usage, watermark status, and available plans. It also explicitly carves out the self-hosted case, so an agent can tell immediately whether this tool applies to the running instance.
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 context is implied by the hosting distinction ('Hosted instances…', 'On a self-hosted Reelsaw this answers that billing is not enabled'), which is genuinely useful for deciding whether it's worth calling. However, it never names the obvious alternative, billing_checkout_url, nor states the condition that selects one over the other (e.g., view status here, obtain a payment URL there).
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, emphasis, layers (assets, text, sounds), render diagnostics, video/thumbnail/editor links, and what the next render will use with where each comes from: style { own, effective, from: clip|project|default }, framing { own, effective: { mode, adjust, sections }, from }, bumpers { own, effective } (intro/outro). 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 the safety profile is covered; the description adds genuine context beyond that by promising 'Returns the clip object' and explaining that the response includes both 'own' and 'effective' values with their source (clip|project|default). That inheritance behavior is the kind of thing an agent cannot infer from structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded and the usage hint is short and actionable. The opening sentence is a long enumeration of return fields that borders on run-on, but each item tells the agent something exists in the response, so little of it is wasted.
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's enumeration of returned fields and the own/effective/from resolution rules are essential and present. It also explains the render-status polling pattern. What is missing is minor (e.g., what happens with an invalid or stale id).
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 already carries a description ('Clip id (from get_project or search_clips)'). The description adds nothing about the id format, so the schema does the work and 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 and resource ('Everything about one clip') and then enumerates exactly what that means (text, bounds, scores, emphasis, layers, render diagnostics, links). It explicitly distinguishes itself from get_project ('lists all clips in brief'), so an agent can choose between them 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?
Names a concrete alternative (get_project for the brief list) and gives an explicit operational trigger: 'poll this after an edit to see the render finish (status done).' That is clear when-to-use guidance, though it does not cover when to prefer get_clip_captions or search_clips instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_clip_captionsGet clip captionsARead-only
The captions of a clip's last render as an SRT or WebVTT file: the same lines and times as the video (intro included), even when the style has captions off. Returns the file text; VTT with words: true adds karaoke word timestamps. A clip rendered before caption files existed answers that it needs a re-render (rerender_clip).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Clip id (from get_project or search_clips) | |
| words | No | VTT only: add a <timestamp> before every word after the first in each cue | |
| format | No | srt (default) or vtt | srt |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond readOnlyHint=true, the description discloses that captions mirror the rendered video's lines and times including the intro, that they exist even when the style has captions off, that the return value is file text, and that a clip rendered before caption files returns a message pointing at rerender_clip. That stale-render behavior is exactly the kind of non-obvious trait the description must carry.
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, front-loaded with what the tool returns, then parameter nuance, then the failure case. Dense but every sentence earns its place; slight compression could improve readability.
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, but the description states the return value is file text and explains what that text contains. Combined with the stale-render case, an agent has everything needed to call it correctly and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds meaningful plain-language semantics: words: true yields karaoke-style word timestamps and only applies to VTT. That clarifies the interaction between the two optional parameters beyond what the schema states.
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 names a specific verb+resource (fetch the captions of a clip's last render) and pins down the exact artifact form (SRT or WebVTT file text). The phrase 'a clip's last render' distinguishes it from project-level transcript siblings such as get_transcript and get_project_transcript_file.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly states the context in which this tool applies (captions of the last render, intro included, regardless of style settings) and routes the stale-render case explicitly to rerender_clip. It doesn't explicitly contrast with get_clip or get_transcript, but the trigger conditions are clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_email_preferencesEmail preferencesBRead-only
Which optional emails you get, by topic. Returns { emailEnabled, emailPreferences: { ready } }; ready is the note sent when projects finish while you are away. emailEnabled false means this instance sends no mail at all.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already tells the agent this is a safe read, and the parameterless schema confirms nothing is mutated. The description does add real behavioral value by naming the returned fields and explaining what `ready` means, but it stops short of saying whether preferences are per-instance or per-user, or what an empty result implies.
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 the core answer front-loaded and the return shape immediately after. No filler, though the field walkthrough is slightly terse and could be grouped more cleanly.
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 carries the burden of explaining the return value and does so, covering both emailEnabled and the ready note. For a trivial parameterless read tool that is close to sufficient; only the relationship to the setter tool is left implicit.
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?
Zero parameters, so the baseline is 4. The description uses its space on output field semantics instead, which the schema cannot cover, so nothing is lost by the absence of parameter discussion.
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 identifies the resource concretely: which optional emails the instance sends, broken down by topic, with the top-level return shape given. The verb is implied (a read/query) rather than stated outright, and the sibling set_email_preferences is never named, so the agent must infer the read-vs-write split itself.
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 statement of when to call this versus set_email_preferences or get_instance_settings. The note that emailEnabled false means no mail is sent is interpretive context, not a usage condition, so an agent gets no routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_failureGet a failed project or clipARead-only
Admins only: one failed project or clip (title, owner email, stage, full recorded reason, when). A clip whose project also failed is not returned — retry the project. Returns the item or null if it is gone (retried, deleted). Hosted non-admins are refused.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id or clip id | |
| kind | Yes | project = the whole pipeline stopped; clip = one clip failed to prepare or render |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, and the description adds substantial context beyond that: admin-only authorization, refusal behavior for hosted non-admins, a null return when the item is gone (retried or deleted), and the clip/project deduplication rule. These are exactly the behavioral traits an agent cannot infer from structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three compact sentences, no filler. The admin restriction leads, the return payload and the clip-suppression rule follow, and the null case closes it out — front-loaded and dense with 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, yet the description enumerates the returned fields, covers the null result, and documents the authorization boundary. For a two-parameter read tool, an agent has everything needed to call it and interpret the response.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters are already documented, including the kind enum. The description still contributes meaning by tying kind to a behavioral consequence (clip suppression when its parent project failed), which the schema does not convey. Baseline 3 plus that added semantics merits a 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?
Names a specific verb+resource (retrieve one failed project or clip) and immediately enumerates what comes back: title, owner email, stage, full recorded reason, and timestamp. That field list plus the admin restriction makes it unmistakable against siblings like list_failures 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?
Gives concrete routing advice: a clip whose project also failed is not returned, so retry the project instead. That is an explicit alternative path. It stops short of stating when to prefer this over list_failures for enumeration, which is the only real gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_instance_settingsInstance settingsARead-only
Admins only: the instance settings in force (sign-up mode, email verification, captcha, legal links, quotas, upload limits, retention, stall watchdog, update check, health details) and where each comes from. Returns { values, env, override, source: { KEY: "env" | "db" }, ignored: { KEY: reason }, groups, help, updatedAt, updatedBy }; secrets are masked.
| 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 the description isn't burdened with safety claims. It still adds real value by disclosing that secrets are masked and that provenance (env vs db) and ignored keys are part of the result — traits an agent needs to interpret the output correctly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose and audience, then the return shape. The long parenthetical setting list is dense but earns its place by telling the agent what is covered before it calls.
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 present, the description fully compensates by spelling out the return object's fields (values, env, override, source, ignored, groups, help, updatedAt/updatedBy). Nothing needed to call or interpret it 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 the baseline is 4 by rule. No parameter meaning is missing because there is nothing to document.
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 instance settings in force') and enumerates the domains covered (sign-up mode, quotas, retention, etc.) plus provenance. An agent can distinguish it from the mutation sibling set_instance_settings 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?
'Admins only' gives a clear access prerequisite, and the read-only framing implies inspection usage. But it never names set_instance_settings as the write alternative or says when to prefer this tool over sibling lookups like check_for_update or get_billing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_media_linksGet share linksA
Links anyone can download without an Authorization header, for a scheduler (Buffer, Metricool), Instagram's video_url, Zapier/Make or a person. Returns { clips: [{ clipId, links: { clip, thumb, srt, vtt } }], export } with each link's { linkId, url, expiresAt }; unrendered clips say why. The active link is reused unless label or ttlDays ask for a separate one. A link serves the current render until it expires or revoke_media_link turns it off.
| Name | Required | Description | Default |
|---|---|---|---|
| kinds | No | Which files (default: clip): clip = the MP4, thumb = its JPEG, srt / vtt = its captions | |
| label | No | A name for a separate link you can revoke on its own, e.g. "Buffer queue" | |
| export | No | Also a link to the zip of these clips with YouTube/TikTok metadata | |
| clipIds | No | Only these clips; omitted = every rendered clip | |
| ttlDays | No | Days the links last (capped by the instance); null = never expires where allowed | |
| 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 burden and does so: it discloses the security-relevant trait that links bypass Authorization, the side effect that this GET-shaped tool mints/reuses links, the reuse rule ('the active link is reused unless label or ttlDays ask for a separate one'), and expiry/revocation semantics. It also explains what happens for unrendered clips ('say why'), which prevents blind retries.
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 key distinguishing fact (public, no-auth download links) followed by return shape and link-lifecycle rules. The first sentence is dense with consumer examples but each serves agent selection; nothing is padding, though the prose is tighter-packed than ideal.
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, yet the description inlines the return structure ({ clips: [{ clipId, links: { clip, thumb, srt, vtt } }], export }) with per-link { linkId, url, expiresAt }. Combined with reuse/expiry/revocation rules and the unrendered-clip failure mode, an agent has everything needed to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 by tying label and ttlDays to link-identity behavior ('ask for a separate one') — that interaction is not expressed in the schema descriptions. It also frames the non-obvious default behavior (active link reuse) that the parameters override.
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 — returns share links that anyone can download without an Authorization header — plus the shape of the result. It is clearly distinguishable from the adjacent list_media_links and revoke_media_link tools, which it implicitly references via revoke semantics.
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 consumer scenarios (Buffer/Metricool schedulers, Instagram's video_url, Zapier/Make, or a person) that tell an agent when to reach for this tool. It stops short of explicitly contrasting with list_media_links (which presumably lists already-created links) or stating when not to use it, so it is clear context rather than full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
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_defaultsGet project defaultsARead-only
The settings every new project starts with (Settings, Project defaults): language, vocabulary, instructions, focus, clip lengths, pauses, caption look and refine steps. Returns { projectDefaults }; keys you never set are absent and use the built-in value. Change them with set_project_defaults.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint is already declared by annotations, but the description adds real behavioral detail beyond that: the response shape '{ projectDefaults }' and the crucial semantics that unset keys are absent and fall back to built-in values. This is exactly the kind of return-value subtlety annotations cannot convey, though nothing is said about permissions or rate limits (low relevance for a read).
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 sentences, no padding: the identity/scope of the resource comes first, the return shape and absent-key semantics second, the handoff to set_project_defaults last. 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 zero-parameter read tool with no output schema, the description supplies what is missing from structured data: the returned key name, the absent-key fallback rule, and the companion mutation tool. Nothing an agent needs in order 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?
The tool takes no parameters, so the baseline is 4. The description correctly implies no inputs are needed and spends its words on the return payload instead.
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 the specific resource ('the settings every new project starts with') and enumerates the fields it covers (language, vocabulary, instructions, focus, clip lengths, pauses, captions, refine steps). The closing sentence names its mutation counterpart set_project_defaults, so the agent can distinguish it from the rewrite 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?
Clearly frames the tool as the read side of project defaults and explicitly routes mutation to set_project_defaults. It does not state when-not conditions (e.g., when get_project would be preferred for a specific project's settings), but for a zero-argument getter the intended context is unambiguous.
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 (the same events the Activity panel shows; live progress ticks are not stored): 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?
With readOnlyHint already declaring safety, the description adds genuinely new behavioral context: live progress ticks are not stored (so polling will not surface in-flight state), the order is newest-first, and the return shape is given. It stops short of saying what a truncated result looks like or how far back history goes.
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 what the tool is and immediately followed by the qualifier about unstored ticks and the return shape. Every clause carries information, though the parenthetical and clause list make it slightly harder to scan than a purely linear 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, but the description supplies the return shape and event taxonomy, which is the key missing piece. The only real gap is pagination/truncation semantics for limit, which matters for an agent that may need older events.
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 both id and limit are already fully documented in the schema, including the 1-200 range and default. The description adds only the ordering guarantee, not any meaning for the parameters themselves, 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 resource (the project's pipeline history) with a concrete scope and ordering (newest first), plus the exact event kinds returned. It explicitly contrasts with get_project's current-state view, so an agent can pick between them 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 use case ("find out why something failed or is slow") and names the alternative (get_project) with the condition that selects it. It does not address the other overlapping siblings such as get_failure or get_queue, which also surface failure details, so the routing 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.
get_project_transcript_fileGet transcript fileARead-only
The project transcript as an SRT or WebVTT subtitle file, one cue per transcript segment, in source-video seconds. Returns the file text; VTT with words: true adds word timestamps. Use get_transcript to read it as plain timed lines instead.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| words | No | VTT only: add a <timestamp> before every word after the first in each cue | |
| format | No | srt (default) or vtt | srt |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already covers the safety profile, and the description adds real value on top: returns file text (not a parsed structure), timing is in source-video seconds, and words:true only affects VTT word timestamps. It doesn't mention failure behavior when no transcript exists, which is the one behavioral gap for a retrieval 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 sentences, front-loaded with the output format and segmentation, then the words/format behavior, then the sibling pointer. Nothing is redundant with the schema or annotations.
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 does the job of describing what comes back (file text, one cue per segment, source-video seconds). Complete for the happy path, though it never says what happens if the project has no transcript or is still processing, which matters in a pipeline with wait_for_project and reanalyze_project siblings.
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 semantics the schema lacks: that cue timing is expressed in source-video seconds, and that the words flag produces a per-word <timestamp> marker in the cue rather than a separate field. That clarifies intent beyond the enum/default documentation.
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 (get the project transcript file) and pins the output form: SRT or WebVTT subtitle file, one cue per segment, in source-video seconds. It explicitly distinguishes itself from the closely named sibling get_transcript by contrasting file-based subtitles with plain timed lines.
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?
'Use get_transcript to read it as plain timed lines instead' names the alternative and the condition that selects it, so an agent can route between the two transcript tools without opening either schema. The subtitle-file vs timed-lines distinction is the exact decision an agent faces here.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_queueQueue summaryARead-only
Admins only: waiting, running and retrying job counts per pipeline stage with when the longest wait began (oldestWaitingAt), plus the jobs currently in flight (project title, attempt, started, and a retrying job's lastError). Returns { queues, active, truncated, error? }. Failed work is list_failures, not this. Hosted non-admins are refused.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond readOnlyHint=true, it discloses authorization behavior (non-admins refused on hosted) and a truncation flag in the response, plus what error may appear. That is meaningful operational context an agent cannot infer from the annotations. It does not state rate limits or how partial results are ordered/filled when truncated, which keeps it off a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, with the admin gate and the metric list front-loaded before the return shape and the list_failures exclusion. Dense but essentially waste-free; the parenthetical field enumeration is the only slightly heavy part.
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 carries the return-value burden and does so by naming the top-level shape { queues, active, truncated, error? } and the key fields (project title, attempt, started, lastError). Inner structure of queue entries and truncation behavior are only sketched, which is the remaining gap for a read-only summary tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; baseline is 4. The description correctly does not invent arguments and instead spends its words on scope and return shape.
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 resource (queue) and what it reports — waiting/running/retrying counts per pipeline stage plus in-flight jobs — in concrete terms. It explicitly distinguishes itself from the sibling list_failures ("Failed work is list_failures, not this"), so an agent can pick between them 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?
Gives a hard prerequisite ("Admins only", hosted non-admins are refused) and routes the failed-job case to list_failures. It stops short of naming other adjacent alternatives (e.g. list_workers, list_failures sibling set) or the situations that make this the right call vs. a project-status tool, but the usage context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_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.
import_transcriptImport transcriptADestructive
Use an SRT or WebVTT file as the project's transcript instead of transcribing: right after create_project (only the video is fetched) or on a done or failed project (it then re-cleans the transcript and picks clips again; accepted and rejected fixes, cuts and corrections on the old transcript are lost for good). Give exactly one of text, uploadId or url. Returns { format, cues, words, warnings, message }; follow with wait_for_project.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| url | No | http(s) link to a public .srt/.vtt file | |
| text | No | The contents of the .srt or .vtt file | |
| format | No | auto (default) decides from the WEBVTT header | auto |
| language | No | Language code of the text, e.g. en, es, ja (default: the existing transcript's, else unknown) | |
| uploadId | No | Upload id of an .srt/.vtt file sent to POST /api/upload |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only flag destructiveHint=true; the description supplies the actual consequence: the transcript is re-cleaned, clips are picked again, and 'accepted and rejected fixes, cuts and corrections on the old transcript are lost for good'. That is exactly the irreversibility context an agent needs before a destructive call. It stops short of noting auth requirements or size/rate constraints, so a 4 rather than 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the purpose, then the source constraint, then the return shape and next step — no filler. The first sentence is long with nested parentheticals, which slightly slows parsing but every clause carries distinct 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 6-parameter destructive tool with no output schema, the description covers applicability states, the mutually exclusive source inputs, the destructive consequence, the return shape, and the required follow-up call. Nothing an agent needs to invoke it safely and 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 would be 3, but the description adds a constraint the schema does not encode: exactly one of text, uploadId or url must be supplied (the schema only requires id). That meaningfully reduces malformed calls beyond what the field descriptions convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Use an SRT or WebVTT file as the project's transcript') and explicitly contrasts it with the default path ('instead of transcribing'), which distinguishes it from siblings like reanalyze_project or refine_project. An agent can identify the operation 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 concrete lifecycle states where it applies ('right after create_project (only the video is fetched)' and 'on a done or failed project'), and prescribes the follow-up call ('follow with wait_for_project'). It also gives the mutual-exclusion rule ('Give exactly one of text, uploadId or url'), leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_decisionsList decisionsARead-only
Your decision log: what you accepted, rejected, cut, corrected, edited, deleted or restored, newest first, kept after a project is deleted so Reelsaw learns from it. Returns { summary: { enabled, total, projects, byKind }, items: [{ id, kind, explicit, projectId, clipId, before, after, context, models, source, createdAt }], nextCursor, total }. kinds are fix.* (transcript fixes) and clip.*; clip.replaced (explicit false) is a pick a re-analyze replaced.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | Only this kind of decision | |
| limit | No | Page size (1-200, default 50) | |
| cursor | No | nextCursor from the previous page | |
| projectId | No | Only decisions about this project (it may already be deleted) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, while the description adds meaningful behavior: decisions are returned newest first, are retained after project deletion so the system can learn from them, and include summary/item/pagination fields. It also explains the special meaning of clip.replaced and explicit=false. These details go well beyond the annotation, though permission or rate-limit behavior is not discussed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and then moves efficiently into return shape and kind semantics. It is fairly dense but each part contributes useful information, with only mild run-on density in the first sentence.
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 list tool with no output schema, the description supplies the return structure, ordering, pagination field, retained-after-deletion behavior, and kind semantics. Combined with full schema coverage and readOnlyHint, it gives an agent enough context to call and interpret the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3, but the description adds useful semantic grouping for kind values as fix.* transcript fixes versus clip.* decisions, and clarifies the meaning of clip.replaced with explicit=false. It also notes that projectId may refer to an already-deleted project, reinforcing the schema's 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?
The description clearly states a specific verb and resource: it lists the user's decision log, including accepted/rejected/cut/corrected/edited/deleted/restored decisions, newest first. It is specific enough to distinguish this from generic listing tools, though it does not explicitly name sibling tools such as export_decisions or forget_decisions.
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 as viewing the decision history, but the description gives no explicit when-to-use guidance and does not contrast this tool with nearby alternatives like export_decisions, forget_decisions, or set_learning. An agent can infer the purpose, but routing between decision-related siblings is left to the agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_deletedList deleted itemsARead-only
Restorable deletes (the Deleted page): one newest-first list of projects, clips of live projects, library items and templates. Returns { items: [{ kind, id, title, deletedAt, purgeAt, storedBytes, canPurge, … }], total, truncated } (max 200) plus keepDays / libraryDays / templateDays. purgeAt null = kept until deleted forever. restore_project / restore_clip / restore_asset / restore_layer_template bring them back; purge_project / purge_clip / purge_asset / purge_layer_template remove them for good.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true and the description is fully consistent, adding behavior the annotation can't: max 200 items with a truncated flag, retention windows (keepDays/libraryDays/templateDays), and that purgeAt null means kept until deleted forever. This is exactly the extra context the annotation bar asks for.
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 scope and the newest-first ordering, then the return shape, then the sibling routing. Dense and nearly waste-free, though the item-shape enumeration and the four sibling name pairs make it a long single paragraph that could be split for scanability.
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 full burden of describing the return value and does so precisely (items fields, total, truncated, max 200, retention fields, purgeAt semantics). 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?
Zero parameters, so the baseline is 4; the description has no parameter semantics to add and none are needed. It redirects that space into return-shape detail instead.
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 ('one newest-first list of projects, clips of live projects, library items and templates'), plus the scope 'Restorable deletes (the Deleted page)'. That scope qualifier cleanly separates it from list_projects, search_clips and the restore_*/purge_* siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: restore_project/restore_clip/restore_asset/restore_layer_template bring items back, purge_* removes them permanently, implying this tool is the read-only discovery step before either. It doesn't state an explicit 'do not use for X' exclusion, which keeps it from a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_failuresList failed workARead-only
Admins only: failed projects and clips across the instance (owner email, stage, reason, when). A failed project's clips are not listed separately — retry the project. Returns { items, nextCursor, total, limit, truncated }. Filter with q (substring of the error), stage, since (ISO time). Hosted non-admins are refused.
| Name | Required | Description | Default |
|---|---|---|---|
| q | No | Case-insensitive substring of the recorded error (e.g. disk, encoder, model) | |
| limit | No | Page size, default 50 | |
| since | No | ISO timestamp; only failures updated at or after this time | |
| stage | No | Pipeline stage that failed | |
| cursor | No | nextCursor from the previous page |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnlyHint annotation: it discloses the admin-only permission requirement, the hosted-tier refusal behavior, the aggregation semantics (child clips are collapsed into the parent project failure), and the truncation/nextCursor pagination behavior. These are exactly the traits an agent needs before calling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense and front-loaded: access restriction first, then scope, then the clip-aggregation caveat, then return shape, then filters. Slightly crammed, but nearly 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?
There is no output schema, yet the description names the return keys ({ items, nextCursor, total, limit, truncated }) and explains pagination via cursor. Combined with the auth and filtering notes, an agent has enough to call this correctly without inspecting anything further.
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 all five parameters are already documented with examples and formats. The description only restates q, stage, and since at a high level and says nothing about limit or cursor, so it adds marginal value over the schema — baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('failed projects and clips across the instance') plus the fields returned (owner email, stage, reason, when). It is clearly distinct from get_failure (single item) and retry_failures in intent, though it never names a sibling explicitly.
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 scopes the audience ('Admins only', 'Hosted non-admins are refused') and gives a concrete routing rule: a failed project's clips are not listed separately, so retry the project instead. It also tells the agent which filters to apply (q, stage, since), though it doesn't contrast against get_failure or retry_failures by name.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_layer_templatesList layer templatesARead-only
Your layer templates (layers that fit any clip length, plus an optional intro / outro), newest first. Returns { items: [{ id, name, layerCount, layers, bumpers, updatedAt }], nextCursor, total, deleted } (nextCursor goes in cursor; deleted = restorable). A layer has the clip-layer fields plus timing { mode, start, end, minSec, maxSec }: head = seconds after the start; tail = seconds before the end (end 0 = the very end); fill = whole clip; relative = fractions 0-1 of the length, held between minSec and maxSec
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Templates per page (1-500, default 100) | |
| cursor | No | nextCursor from the previous page; omit for the first page |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnlyHint already declaring safety, the description adds substantial behavior: newest-first ordering, pagination via nextCursor, a deleted field meaning restorable items, and detailed semantics for layer timing modes. This goes well beyond what annotations provide and gives an agent operational context for interpreting results.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the tool's purpose and has no filler, but it is a single dense run-on sentence with many nested clauses. The information density is justified because there is no output schema, though readability could be improved with structural separation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must carry return-shape information, and it does: it names the item fields, explains nextCursor/total/deleted, and defines the timing object used by layers. For a read-only listing tool with only two simple parameters, this is complete enough for an agent to call 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 coverage is 100%, so the baseline is 3. The description adds meaningful semantics beyond the schema by explaining that nextCursor goes into cursor when paging, which clarifies how the pagination parameter is meant to be used.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb-and-resource pair: it lists the caller's layer templates, defines them as reusable layers plus optional intro/outro, and states the default ordering (newest first). That clearly separates it from sibling mutation tools like save_layer_template, update_layer_template, apply_layer_template, and delete_layer_template.
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 verb 'Your layer templates' and by the pagination details, but there is no explicit when-to-use guidance, prerequisite note, or alternative mentioned. An agent can infer this is the listing/read tool, but the description does not route it against alternatives such as get_clip or apply_layer_template.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_media_linksList share linksARead-only
Your share links, newest first. Returns { items: [{ id, kind, projectId, clipId, title, url (masked), label, source, state (active | expired | revoked), expiresAt, lastUsedAt, useCount }], nextCursor, total }. Use get_media_links for a full URL.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Links per page (1-100) | |
| active | No | Only links that still work | |
| clipId | No | Only this clip's links | |
| cursor | No | nextCursor from the previous page | |
| projectId | No | Only this project's links |
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 genuinely non-obvious behavior by disclosing that URLs are masked, that items carry a state enum with active/expired/revoked values, and that pagination is cursor-based via nextCursor. Nothing here contradicts the read-only 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?
Two sentences, zero filler, with scope and ordering front-loaded and the alternative routing in the second sentence. The return-shape enumeration is long but dense with useful field-level detail that no output schema provides.
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, describing the returned fields, the cursor, and the total is exactly the right compensation, and the masking caveat prevents misuse of the url field. The only gap is that the available filters are never surfaced in prose, though the schema covers them fully.
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, active, clipId, cursor, and projectId are all documented in the schema. The description adds no parameter meaning beyond that — it never mentions the filtering options — so it sits at the baseline rather than exceeding it.
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 the resource ('Your share links') and the ordering ('newest first'), which pins down this as a personal-scope list operation distinct from get_media_links. It never uses an explicit list verb, but the name plus scope wording is unambiguous enough for an agent to select it.
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 names a sibling alternative and the exact condition that selects it: 'Use get_media_links for a full URL.' It gives no guidance on when this tool should not be used (e.g., filtering for a specific project vs. browsing all), so it falls short of explicit 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.
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. deleted: true lists restorable deletes (storedBytes still count until purge_project). For every kind of restorable delete (projects, clips, library, templates) use list_deleted. 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?
With readOnlyHint already declaring safety, the description still adds real behavior: result ordering, the exact response envelope, the nextCursor pagination loop, and that deleted items' storedBytes still count until purge_project. That last point is non-obvious mutation-adjacent context an agent would otherwise miss.
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?
Densely packed, front-loaded with scope and ordering, and every clause carries information (response shape, pagination, deleted semantics, alternatives). It is a single long block rather than broken up, and the return-shape serialization is slightly verbose, but nothing is 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?
No output schema exists, and the description supplies the full response envelope, pagination mechanics, deleted-mode caveat, and sibling disambiguation. For a three-param read-only list tool, 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 earns extra: it explains that nextCursor must be passed as cursor for the next page (the pagination idiom) and clarifies what deleted:true really means (restorable deletes whose bytes still bill). It adds marginal but useful meaning beyond the schema strings.
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 the resource ('Your projects') and ordering ('most recently updated first') and implicitly the list verb, while naming the siblings it is not (get_project for a single project, search_clips for word search, list_deleted for other delete kinds). An agent can distinguish it from every sibling 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?
Explicit routing: 'Use get_project for one project's clips, search_clips to find by words', and 'For every kind of restorable delete (projects, clips, library, templates) use list_deleted'. That covers when to use this versus alternatives, including the subtlety that deleted=true only lists projects.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_releasesList releasesARead-only
Published Reelsaw versions from GitHub (reelsaw.com/releases): tag, date, a short summary and the change notes. Returns { releases, total, windowDays, commits, commitDays, releaseDays, truncated, fetchedAt, sourceUrl, error }; pass tag for one version. Cached for an hour.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | Only this tag or version (v0.19.1 or 0.19.1) | |
| limit | No | How many releases to return (1-100, default 20, newest first) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, so the description usefully adds that results are 'Cached for an hour', names the upstream source URL, and discloses envelope fields including truncated and error signals. It doesn't discuss rate limits or behaviour when the upstream fetch fails, but the caching and error-field disclosure go meaningfully beyond 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?
Two compact sentences, resource and source front-loaded, with the response envelope listed inline rather than prose-padded. The key enumeration is dense but earns its place given the absence of an output 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?
With no output schema, the description takes on the return-shape burden and does so by enumerating the envelope fields including truncated and error. Caching and source are covered; the only gap is how limit and tag interact, which is minor for a read-only listing 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?
Schema coverage is 100%, so both parameters are already documented in the schema, and the description only adds the passing notion that a tag returns a single version rather than a list. The limit parameter and the interaction between tag and limit are not addressed, so the description does not materially exceed 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 specific verb+resource ('Published Reelsaw versions from GitHub') and immediately enumerates the fields returned (tag, date, summary, change notes), so the agent knows exactly what this yields. It is clearly distinct from app-update siblings like check_for_update because it names the release source and URL.
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 clause 'pass tag for one version' gives implicit guidance on how to narrow the call, and 'newest first' in the schema implies the default listing behaviour. However, there is no explicit when-to-use/when-not guidance and no comparison to the nearest sibling, check_for_update, which an agent could plausibly confuse with this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_transcript_flagsList transcript fixesARead-only
The fixes Reelsaw made or suggests in a project's transcript: misheard names, fillers and repetitions to cut, and your own cuts and corrections. Returns { total, flags: [{ id, kind, subkind, status, start, end, heard, suggested, replacement, confidence }] }; status pending waits for your decision. Use the ids with review_transcript_flags.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| limit | No | Most fixes to return (1-500, default 100) | |
| status | No | Only fixes in this state; omitted = all (pending = waiting for review, auto = applied automatically) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnlyHint already declaring the safety profile, the description adds real value: it discloses the return shape, the meaning of the flags' content ('misheard names, fillers and repetitions to cut, and your own cuts and corrections'), and the status semantics that drive the next action. It stops short of describing ordering, pagination/truncation behavior at the limit, or what an empty result looks like.
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 resource and its contents, then the return shape, then the actionable next step — no filler sentences. The inline brace-notation return schema is dense but earns its place since no output schema exists.
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, three-parameter listing tool with no output schema, the description supplies the return structure, the flag taxonomy, and the workflow link to review_transcript_flags — enough to call it correctly. Remaining gaps (result ordering, behavior when limit truncates) are minor for a listing operation.
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 enum descriptions already define pending and auto ('waiting for review', 'applied automatically'), so the description's 'status pending waits for your decision' largely restates structured data. The description adds indirect context about what the ids are for, but no new constraint or format details beyond the schema, so baseline 3 is warranted.
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 fixes Reelsaw made or suggests in a project's transcript') and enumerates the categories of flags returned, which distinguishes it from get_transcript and from the mutating sibling review_transcript_flags. An agent can tell at a glance that this is a read-only enumeration of reviewable corrections.
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 forward: 'Use the ids with review_transcript_flags', and explains that 'status pending waits for your decision', which frames the review workflow. It does not state when to prefer get_transcript or add_transcript_cut/add_transcript_correction instead, so the exclusion side is implied rather than spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_webhook_deliveriesList webhook deliveriesARead-only
The delivery log, newest first. Returns { items: [{ id, endpointId, eventId, type, projectId, status (pending | sending | delivered | failed | cancelled), attempt, lastStatusCode, lastError, nextAttemptAt, deliveredAt }], nextCursor, total }. Failed deliveries were retried 8 times over about 22 h.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Deliveries per page (1-100) | |
| cursor | No | nextCursor from the previous page | |
| status | No | Only deliveries in this state | |
| projectId | No | Only deliveries about this project | |
| endpointId | No | Only this webhook's deliveries (from list_webhooks) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description adds useful behavioral context: newest-first ordering, the full return shape, status values, and retry behavior for failed deliveries. It does not cover permissions or rate limits, but for a read-only list tool this is strong added transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and then provides return details and retry context. The inline return object is dense but justified because there is no output schema, and every sentence contributes useful 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, the description fully documents the return structure, ordering, status values, pagination fields, and retry behavior. Combined with the complete input schema and readOnly annotation, an agent has enough information to call and interpret the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all five parameters. The description does not add meaning beyond the schema for limit, cursor, status, projectId, or endpointId, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies the resource as a webhook delivery log and states the ordering (newest first), so the agent can tell it is a list operation over delivery records. It does not explicitly differentiate from sibling tools such as list_webhooks or list_failures, which keeps it from a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit guidance on when to use this tool versus alternatives like list_webhooks or list_failures. The retry note is contextual but does not tell the agent when this tool is the right choice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_webhooksList webhooksARead-only
Your webhook endpoints. Returns [{ id, url (masked), description, events, status (active | failing | off), disabledReason, failingSince, lastDelivery }]. Reelsaw POSTs signed JSON (Standard Webhooks headers webhook-id, webhook-timestamp, webhook-signature) to each when a subscribed event happens.
| 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 the safety profile is covered; the description nonetheless adds real behavioral context the annotations do not: URLs are masked, status is a three-valued state (active | failing | off) with accompanying disabledReason/failingSince/lastDelivery fields, and deliveries are signed JSON using Standard Webhooks headers. That tells the agent both what a 'failing' endpoint looks like and how delivery works.
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: the resource identity first, then the exact response fields, then delivery behavior. No filler, no restatement of the title, and the field list is given in a form an agent can parse directly.
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 parameters, the description carries the whole burden of describing the return value, and it does so thoroughly, including edge-state fields like disabledReason and lastDelivery. Minor gaps remain: ordering, whether all endpoints are returned or truncated, and per-endpoint event subscription semantics are unstated.
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 the schema has nothing to explain and the baseline is 4. The description does not need to add argument semantics, and it correctly spends its words on the return payload instead.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening line 'Your webhook endpoints' plus an explicit return-shape enumeration makes clear this is a read of configured webhook endpoints. It is distinguishable from delete_webhook/update_webhook by the read framing and from list_webhook_deliveries by returning endpoint objects (id, url, events, status) rather than deliveries. It never names a sibling explicitly, so differentiation is inferential rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied: you call this to inspect the webhooks currently registered on the account. There is no explicit 'use this when...' or 'do not use this for delivery history, use list_webhook_deliveries instead' statement, and no mention of prerequisites such as authentication or scoping. An agent can guess correctly, but the description does not route it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_workersList workersARead-only
Admins only: every Reelsaw process that has checked in (API, worker, combined app): CPU, memory, disk (free/total MB, -1 = unmeasurable; diskLeasedMB = claimed by jobs in flight), GPU, render slots, queues it listens on, and its jobs. A worker out of disk drops the media queues from queues until it recovers. paused = what it was short of (memory, CPU, disk), null when it has room. Returns { items, live, stale }; stale = no check-in for 45 seconds. Hosted non-admins are refused.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Consistent with readOnlyHint=true and adds substantial context beyond annotations: authorization gating, the 45-second staleness threshold, the -1 unmeasurable sentinel, diskLeasedMB semantics, the out-of-disk queue-drop behavior, and the meaning of `paused` including when it is null. This is exactly the operational detail the annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the access gate, then the payload contents, then the return shape — a sensible order. It is a single dense run-on with many parentheticals, so it is heavier than ideal, but nearly every clause carries semantics an agent needs (sentinels, staleness, queue dropping).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description carries the return contract itself and does: { items, live, stale } with the staleness definition spelled out. Combined with field-level semantics and the auth gate, 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?
The tool takes zero parameters, so the baseline is 4 and there is nothing for the description to disambiguate. The description correctly spends no space on argument 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 (list) and a precisely scoped resource: every Reelsaw process that has checked in, enumerated as API, worker, combined app. The metric inventory (CPU, memory, disk, GPU, render slots, queues, jobs) makes it unmistakable against siblings like get_queue or get_instance_settings.
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 access precondition up front ('Admins only' ... 'Hosted non-admins are refused'), which tells the agent when the call will fail. It does not name an alternative sibling for non-admin monitoring or for queue-level vs fleet-level inspection, so it falls short of explicit when/when-not routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
purge_assetDelete library item foreverADestructiveIdempotent
Permanently remove an already-deleted library upload and its files so the storage is freed (find it with list_deleted). Refused while a project, clip or live template still names it. An item that is not deleted is refused: call delete_asset first. Returns { storedBytes, message }.
| Name | Required | Description | Default |
|---|---|---|---|
| assetId | Yes | Library asset id (from list_deleted) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, so safety is covered structurally. The description still adds non-obvious behavior: refusal when an item is referenced, the prerequisite deletion state, and the return payload { storedBytes, message }. Not mentioning any permission/auth requirement is the only mild 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?
Four short sentences, each carrying distinct information: the action, the discovery pointer, the refusal rule, the prerequisite, and the return shape. The irreversible action is front-loaded with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With only one parameter and no output schema, the description covers everything an agent needs: prerequisites, refusal conditions, and even the return fields. Nothing required for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the sole parameter already documents 'Library asset id (from list_deleted)'. The description points to list_deleted for discovery but adds no format, length, or other semantics beyond the schema, 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 (permanently remove) and resource (an already-deleted library upload and its files), plus the goal (free storage). The two-stage distinction from delete_asset is made explicit, so the agent can tell it apart from the sibling delete tools without reading 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 discovery tool (list_deleted) and states the precondition that the item must already be deleted, with the alternative to call delete_asset first. It also states explicit refusal conditions (referenced by a project, clip or live template), covering both when and when-not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
purge_clipDelete clip foreverADestructiveIdempotent
Permanently remove a deleted clip of a live project and its rendered file so the storage is freed (find it with list_deleted). A clip that is not deleted is refused: call delete_clip first. Clips of a deleted project go with purge_project. Returns { storedBytes, message }.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Clip id (from list_deleted) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint and idempotentHint, but the description adds real value beyond them: the refusal behavior for non-deleted clips, the fact the rendered file is removed and storage freed, and the return shape { storedBytes, message }. There is no output schema, so naming the return fields is a meaningful supplement.
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 destructive action, then prerequisites, then scope alternative, then return value. Nothing is redundant or padded.
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 what it destroys, the required precondition, the per-project alternative, the refusal case, and the response fields. An agent has everything needed to call it correctly and safely.
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's schema description already says 'Clip id (from list_deleted)'. The description repeats that provenance but adds no format, syntax, or constraint detail beyond the schema, 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 ('Permanently remove a deleted clip ... and its rendered file') plus the outcome (storage freed). It is clearly distinguished from sibling mutations like delete_clip (soft delete) and purge_project (project-scoped purge).
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 the prerequisite (clip must already be deleted; call delete_clip first), how to locate the target (list_deleted), and the alternative for a different scope (purge_project for deleted projects). No inference required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
purge_layer_templateDelete layer template foreverADestructiveIdempotent
Permanently remove an already-deleted layer template (find it with list_deleted). Templates hold no media files; this only drops the row. A template that is not deleted is refused: call delete_layer_template first. Returns { ok, message }.
| Name | Required | Description | Default |
|---|---|---|---|
| templateId | Yes | Layer template id (list_layer_templates) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint and idempotentHint, so the bar is lower, yet the description still adds real context: the action is irreversible, templates hold no media files and only the row is dropped, and non-deleted targets are refused. It also states the return shape { ok, message }. Slightly short of 5 only because it doesn't say what happens to any references or downstream state after the row disappears.
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: effect, scope-of-damage, precondition, return value — each load-bearing, with the find-it hint attached to the operation it modifies. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter destructive tool with no output schema, everything an agent needs is present: how to find the target, the sequencing requirement, the blast radius, the refusal behavior, and the return payload.
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 earns an extra point because the schema's own hint for templateId points to list_layer_templates, which lists non-deleted templates that this tool would refuse; the description corrects that by directing the agent to list_deleted instead.
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 (permanently remove) and resource (an already-deleted layer template), and immediately distinguishes itself from delete_layer_template, the sibling that performs the soft delete. Against a large sibling set containing delete_/purge_/restore_ variants, an agent can pick this one 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?
Explicit preconditions and routing: locate the record with list_deleted, and if the template is not yet deleted the call is refused so delete_layer_template must be run first. This is exactly the when/when-not/alternative triad the dimension asks for.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
purge_projectDelete project foreverADestructiveIdempotent
Permanently remove a deleted project and its files so the storage is freed (find it with list_deleted or list_projects deleted: true). Minutes, hourly creates and first-video-free are not refunded. A project that is not deleted is refused: call delete_project first. What you decided about it (accepted and rejected fixes, clip edits) stays in your decision log so Reelsaw keeps learning from it, unless forgetDecisions is true. Returns { storedBytes, forgottenDecisions, message }.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects with deleted: true) | |
| forgetDecisions | No | Also forget what Reelsaw learned from this project (its entries in the decision log); default false keeps them |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the destructiveHint/idempotentHint annotations, it discloses what is irrecoverable, that billing artifacts (minutes, hourly creates, first-video-free) are not refunded, and that decision-log entries survive unless forgetDecisions is set. That is exactly the side-effect detail annotations cannot express.
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 destructive action and its scope, then preconditions, then side effects, then return shape. Dense and mostly waste-free, though the parenthetical and the return-value sentence pack several ideas into one long line.
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 shape ({ storedBytes, forgottenDecisions, message }), the refusal case, and the non-refund policy, which covers everything needed to invoke a destructive purge correctly. Nothing material is left undocumented for a 2-parameter 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?
Schema coverage is 100%, so baseline is 3; the description adds real meaning by framing forgetDecisions as a learning-retention tradeoff ('Reelsaw keeps learning from it, unless forgetDecisions is true') rather than just a flag. The id parameter's provenance is reinforced from both the schema and the guidance in the usage sentence.
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 ('permanently remove a deleted project and its files') plus the purpose (freeing storage), which cleanly separates it from delete_project (soft delete) and from purge_clip/purge_asset siblings. An agent can tell what it destroys 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?
Gives explicit preconditions ('A project that is not deleted is refused: call delete_project first') and names the discovery tools to obtain the id (list_deleted or list_projects with deleted: true). It also states the condition under which the optional forgetDecisions behavior applies, leaving no routing inference to the agent.
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, name fixes and the on-screen text scan on, filler removal off). Set refineDisfluency / disfluencyLlm true to opt into filler removal, refineEntities / refineScenes false to skip those steps (instance Pipeline gates must be on). |
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 preservation of created/edited clips, replacement of untouched AI picks, restorability via restore_clip 'for a while,' the immediate return shape { kept, replaced }, and the background picking behavior requiring wait_for_project.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but front-loaded: purpose, preservation rules, return behavior, async follow-up, and alternatives are all covered in a few sentences with no wasted text.
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 tool with a deeply nested settings object and no output schema, the description supplies the key missing context: what is kept vs replaced, that picking is asynchronous, how to wait for completion, and which sibling tools cover adjacent operations.
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 detailed settings fields are already documented in the input schema. The description only says 'optionally with new settings' and adds no parameter-level meaning beyond that, which is the expected baseline 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?
The description states a specific verb and resource: pick clips again from the existing transcript, optionally with new settings. It distinguishes this from update_project and retry_project explicitly, so an agent can select the correct tool 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?
It gives clear when-to-use context (needs a transcript, optionally new settings) and names the alternative tools for adjacent operations: update_project for saving settings only, and retry_project for resuming a failure. Exclusions are explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
refine_projectRefine projectADestructive
Re-run refine steps on the existing transcript: entities (name spelling), disfluency (filler and repeat cuts), scenes (shot cuts); all three when steps is omitted. Optionally set the vocabulary (names and terms, comma separated; empty string clears it) first. Fixes you accepted or rejected may be replaced. Clips re-render afterwards. Returns { ok, steps }; then wait_for_project.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| steps | No | Which refine steps to re-run; default all | |
| vocabulary | No | Names and terms the transcript should spell this way; empty string clears it |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Even though destructiveHint=true is annotated, the description adds substantive consequences beyond it: accepted/rejected fixes may be replaced, clips re-render afterwards, and vocabulary can be cleared with an empty string. It also discloses the return shape ({ ok, steps }), which the tool has no output schema for.
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 core action and its variants come first, then side effects, then the return value and follow-up. No sentence is filler, and semicolon-separated clauses keep it compact.
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 three-parameter mutation with no output schema, the description covers the step semantics, vocabulary lifecycle, destructive consequences, re-render side effect, return shape, and the correct follow-up call. 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 coverage is 100%, so the schema already documents id, steps and vocabulary. The description adds only marginal meaning, notably the comma-separated format for vocabulary and the default-all behavior for steps, both of which the schema largely covers already.
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 (re-run) and resource (refine steps on the existing transcript), and enumerates the three step types with parenthetical clarification of what each does. It does not distinguish itself from close siblings like reanalyze_project or retry_project, which is the only gap.
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 clear operating context: steps default to all three when omitted, and vocabulary can optionally be set 'first'. It also routes the agent's next action ('then wait_for_project'), but never states when to prefer this over reanalyze_project or retry_project.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
report_issueReport an issueARead-only
A download link for an issue-report zip (the same file Report an issue in the app saves; admins may include instance-wide diagnostics). Returns { url, filename }; GET the url with the same Authorization header as this server. Admins may set instance true to include unfinished work, failed jobs, usage and error logs across every account, for queue, disk or machine problems that are not just one project. On hosted instances with telemetry, non-admins cannot download a zip.
| Name | Required | Description | Default |
|---|---|---|---|
| logs | No | Include this project's log lines (default true) | |
| source | No | Include the source video file (default false) | |
| system | No | Include versions, machine resources, queue counts and recent errors (default true; ignored when not allowed) | |
| clipIds | No | Clips the problem shows up in (from get_project) | |
| allClips | No | Include every rendered clip (default false) | |
| instance | No | Admins only: include unfinished work, failed jobs, usage and error logs across every account | |
| previews | No | Include thumbnails and the selected clips' videos (default true) | |
| projectId | No | Project the report is about (from list_projects); omit for an account- or instance-level report | |
| description | Yes | What went wrong (a sentence is enough) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say readOnlyHint=true, which the description is consistent with (nothing server-side is mutated; a zip is generated for download). Beyond that, it discloses the two facts an agent would otherwise get wrong: the response is a URL that must be fetched with the same Authorization header, and admin/hosted-telemetry access restrictions apply. That is real behavioral context beyond 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?
The return value and the auth step are front-loaded, which is the right priority, and every sentence carries information (URL handling, admin scope, hosted restriction). The opening sentence stacks a parenthetical and a subordinate clause, making it denser than necessary, but there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-parameter tool with no output schema, the description covers the two things an agent cannot infer: the return object shape and the required follow-up GET with an auth header. It also closes the permission gap on `instance` and `description`-only callers. Nothing needed 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%, so the baseline is 3, but the description goes further on the highest-risk parameter: it explains what `instance` is for (unfinished work, failed jobs, logs across every account) and when that scope is appropriate, adding the queue/disk/machine diagnosis rationale the schema lacks. The remaining eight parameters are left entirely to the schema, which is acceptable at full coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states exactly what the tool produces: a download link for an issue-report zip, identified as the same file the in-app 'Report an issue' action saves. It also names the return shape { url, filename }, so an agent knows this is a diagnostics-packaging tool rather than a generic export; no sibling tool in the list does anything comparable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives concrete selection guidance for the key fork: set instance true only for queue, disk or machine problems that are not just one project, as opposed to a project-scoped report. It also flags the precondition that non-admins on hosted instances with telemetry cannot download the zip. What's missing is an explicit trigger phrase for the base case (e.g. 'use when a user reports a bug'), though that is strongly implied.
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, renderQueued, hint } (prepare = it never got its AI title, which runs first and renders afterwards). 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 declare idempotentHint, so the description carries real weight and does: async semantics, that the old video is replaced on completion, typical latency, the follow-up poll via get_clip, and the two-step return shape. The 'prepare' branch is explained as a clip that never received its AI title, which is non-obvious behavior an agent could otherwise misread.
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, then behavior, then the sibling hand-off. Dense but nearly every clause carries information; the nested parenthetical defining 'prepare' is the one spot that costs readability for its value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description documents the return object and the meaning of each field, plus the async polling path and the mutation's effect on prior output. Nothing needed to invoke or interpret the call 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, and the schema already states the clip-vs-project-id distinction. The description reinforces the clip scope but adds no new syntax or format detail beyond the schema; a 4 reflects that the surrounding context (where the id comes from, what the call does with it) is made actionable.
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') plus the trigger conditions, and explicitly distinguishes itself from the plural sibling rerender_clips. An agent can route between the two 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?
Names the exact situations that call for it (rerender:false edits, a failure, an intro/outro change) and explicitly routes multi-clip work to rerender_clips. 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.
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, renderQueued, hint }; 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?
Annotations only declare idempotentHint=true, so the description carries the real burden and delivers: it discloses exactly which clips get queued (finished and failed), which are skipped (rendering), and replacement semantics ('each new video replaces the old when done'). It also names the return keys and the polling path, which is genuinely useful behavior an agent could not infer.
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 flows into queue/skip semantics, return shape, polling, and the alternative. Every sentence earns its place with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, but the description explains the return contract ({ requested, rerendered, skipped, renderQueued, hint }) and the polling follow-up, which is exactly what an agent needs for an async batch operation.
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 params documented, including source tools for projectId and id/range for clipIds. The description adds no further parameter detail beyond what the schema already 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 (queue for re-rendering), resource (several clips of one project), and scope (one step, after edits or failures). An agent can immediately distinguish it from rerender_clip, which is explicitly named.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use conditions (after edits or failures), when-not behavior (still-rendering clips are skipped), and names the alternative 'rerender_clip' for the single-clip case. 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.
resend_webhook_deliveryResend webhook deliveryA
Send a delivery again (a new series of attempts, same webhook-id and body, signed afresh). The webhook must be on. Returns { ok, deliveryId, message }.
| Name | Required | Description | Default |
|---|---|---|---|
| deliveryId | Yes | Delivery id (from list_webhook_deliveries) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description details the internal mechanism of the resend, specifying that it creates a 'new series of attempts,' uses the 'same webhook-id and body,' and signs 'afresh.' This is high-value behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is highly concise. It packs the action, the constraints (webhook status), and the technical details of the resend process into one information-dense sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the absence of formal annotations or output schema, the description is exceptionally complete, detailing the operation, preconditions, and the expected return structure.
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 description adds critical context to the deliveryId parameter by stating its origin ('from list_webhook_deliveries'), which assists the agent in understanding the required input source.
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 tool's purpose is stated clearly: to send a delivery again. It is highly specific and distinct from sibling tools like list_webhook_deliveries or create_webhook.
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 provides a critical usage requirement that the webhook must be on. While it doesn't list formal exclusions, this condition acts as a vital operational guideline for the agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
restore_assetRestore library assetAIdempotent
Bring one of your deleted library items back (the id from delete_asset or list_deleted); restoring an item that is not deleted changes nothing. It does not become a default again. Returns { ok }.
| Name | Required | Description | Default |
|---|---|---|---|
| assetId | Yes | Library asset id (from delete_asset) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the idempotentHint annotation, it discloses two non-obvious behaviors: the call is a silent no-op on non-deleted items, and the restored asset does not regain default status. It also documents the return shape ({ ok }) despite no output schema. Not covered: permissions/auth requirements or whether the restore window is limited.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences, action and source of the id front-loaded, with the edge case and return value in a trailing clause. 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?
For a single-parameter mutation with no output schema, the description covers invocation, the id source, the no-op case, and the response shape. Missing only peripheral context such as whether a purged asset can ever be restored, which matters given purge_asset exists nearby.
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 a source the schema omits: the schema says only 'from delete_asset', while the description also points to list_deleted as a way to obtain the assetId.
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) on a specific resource (deleted library item/asset), and the resource name distinguishes it from restore_project and restore_clip in the sibling list. An agent can identify the correct tool 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 says the id comes from delete_asset or list_deleted, which tells the agent both the precondition and the prerequisite call sequence. It also covers the no-op case (restoring a non-deleted item changes nothing), though it never names explicit alternatives such as restore_project/restore_clip for other resource types.
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 (list_deleted or get_project → 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 list_deleted or get_project → replacedClips) |
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 restored clip is appended to the end of the project's clips, and the return shape { changed, status, needsRerender } is explained with actionable meaning for needsRerender. It does not mention permissions, limits on how long after deletion a restore works, or behavior for purged clips.
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 sentences, front-loaded with the core action and eligibility, then the return value and follow-up. No filler; every clause carries information the 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?
No output schema exists, yet the description documents the returned fields and their interpretation, plus the required follow-up call — everything needed to invoke and act on the result for a single-parameter 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?
Only one parameter, and schema description coverage is 100% with the schema already stating the id comes from list_deleted or get_project → replacedClips. The description repeats that provenance without adding new syntax or constraints, 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+resource (restore a deleted/replaced clip) and scopes which clips qualify — deleted ones or those swapped out by re-analysis — which separates it from delete_clip, purge_clip and restore_project in the sibling list.
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 where to get the id (list_deleted or get_project → replacedClips) and gives the conditional next step (call rerender_clip when needsRerender). Lacks an explicit exclusion, e.g. that purged clips cannot be restored via this tool (purge_clip is a sibling), so it is strong but not complete routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
restore_layer_templateRestore layer templateAIdempotent
Bring back a deleted layer template (the id from list_layer_templates deleted or list_deleted). It does not become a default again. Returns the template.
| Name | Required | Description | Default |
|---|---|---|---|
| templateId | Yes | Layer template id (list_layer_templates) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The only annotation is idempotentHint=true; the description supplements this with two real behavioral facts: the template does not regain default status, and the call returns the template. It does not cover error behavior when the id exists but is not deleted, name-collision handling, or permission requirements, so disclosure is useful but incomplete.
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 followed by provenance and the important caveat. The parenthetical is a little awkwardly worded ('list_layer_templates deleted or list_deleted'), but nothing is wasted.
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, non-destructive restore with a thin annotation set and no output schema, the description covers action, id source, a key state caveat, and the return value. Remaining gaps are minor edge-case behaviors rather than anything 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?
With a single parameter already fully documented in the schema, the baseline is 3. The description's note about where the id comes from mirrors the schema's own 'Layer template id (list_layer_templates)' hint rather than adding new meaning, and it does not clarify format or validation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a clear verb-plus-resource combination ('Bring back a deleted layer template') that tells an agent exactly what the operation does. It does not, however, explicitly distinguish itself from the sibling purge_layer_template, which is the permanent-removal counterpart an agent might confuse it with.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives the precondition ('a deleted layer template'), points to both places to obtain the required id ('list_layer_templates deleted or list_deleted'), and states a key post-condition. It stops short of naming alternatives or exclusions (for example, when to prefer purge over restore), so it is clear context rather than full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
restore_projectRestore projectAIdempotent
Bring back a deleted project with its clips and files (find it with list_deleted or list_projects deleted: true); restoring a project that is not deleted changes nothing. Refused if the account is already at its live project cap. 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?
With only idempotentHint in annotations, the description carries the burden well: it discloses the no-op on non-deleted projects, the account-cap refusal, the processing→failed outcome, and the exact return shape { changed, status }. These are behavioral traits not derivable from structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three compact sentences, each earning its place: action, lookup+no-op, refusal, failure path, and return value. Front-loaded with the primary action and no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter mutation tool with no output schema, the description covers preconditions (must be deleted, cap limit), edge outcomes (processing→failed), and the return payload. 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 id parameter is already documented, so the baseline is met. The description corroborates the source of the id ('from list_deleted or list_projects deleted: true'), adding a small locating hint but little 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?
States a specific verb+resource ('Bring back a deleted project') and adds scope ('with its clips and files'), which clearly separates it from sibling restores like restore_clip and restore_asset. An agent can identify the operation 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?
Explicitly names where to locate the target ('find it with list_deleted or list_projects deleted: true'), states the no-op case for non-deleted projects, the refusal case at the live project cap, and routes to retry_project for projects that come back failed. When/when-not/alternatives are all covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retry_failuresRetry failed workA
Admins only: retry matching failed projects and clips through the same lifecycle as retry_project / rerender_clip (never a raw queue poke). Each item is its own transaction so live-job caps still apply. Cap 50 per call. Returns { retried, skipped, nextCursor }. Writes an admin event failures.retried. Hosted non-admins are refused.
| Name | Required | Description | Default |
|---|---|---|---|
| q | No | Same error substring as list_failures | |
| ids | No | Retry these rows instead of the current filter; omitted = every match of q/stage/since | |
| limit | No | Max items to retry this call, default 50 | |
| since | No | Same since filter as list_failures | |
| stage | No | Same stage filter as list_failures |
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 admin-only access, per-item transactions so live-job caps still apply, the 50-item cap, the response shape, the admin event write, and that non-admins are refused.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the admin-only constraint and action, then quickly covers lifecycle behavior, caps, return shape, event logging, and refusal behavior. Every sentence contributes useful context without 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?
Although there is no output schema, the description supplies the return object shape. Combined with full schema parameter coverage and explicit auth, lifecycle, transaction, cap, and event behavior, it is complete enough for an agent to call this mutation tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the input schema already documents q, ids, limit, since, and stage. The description reinforces the overall filtering model and cap but does not add parameter-level meaning beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: retrying matching failed projects and clips. It distinguishes itself from sibling lifecycle operations by saying it goes through the same lifecycle as retry_project / rerender_clip and is never a raw queue poke.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear usage constraints: admins only, hosted non-admins are refused, and each call is capped at 50 items. It also ties its q/stage/since filters to list_failures, but it does not explicitly state when to choose this bulk retry tool over the single-item retry_project or rerender_clip alternatives.
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.
review_transcript_flagsReview transcript fixesA
Accept or reject suggested transcript fixes (ids from list_transcript_flags), optionally with your own replacement text for an accepted name fix. The transcript is rebuilt; with rerender true (default) clips whose captions overlap a change are re-rendered. Returns { changed, rerendered, needsRerender, flags: [{ id, status, replacement }], hint }.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| rerender | No | Re-render the finished clips whose captions overlap a change (default true); false only saves, re-render later with rerender_clips | |
| decisions | Yes | One decision per fix |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full load, and it does disclose real side effects: the transcript is rebuilt and overlapping captions are re-rendered by default. It omits permissions/credits/re-render cost and reversibility, which matters for a mutation tool, but the core blast radius is stated.
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 front-loaded sentences covering purpose, side effect, and return shape with no filler. The trailing return-shape enumeration is dense but justified by the absence of an output 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?
No output schema exists, so spelling out { changed, rerendered, needsRerender, flags, hint } is valuable, and the rerender side effect is disclosed. What remains missing for a mutation with zero annotations is precondition/authorization context and whether re-rendering consumes credits or is undoable.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the schema already documents id, rerender (including the rerender_clips fallback) and the decisions array. The description adds one genuinely new nuance, that replacement text applies to an accepted *name* fix, but otherwise restates schema content.
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 pair (accept/reject) and resource (suggested transcript fixes), and ties the id space to the sibling list_transcript_flags, so it is unmistakably distinct from add_transcript_correction or import_transcript. The optional replacement behavior is also named inline.
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 '(ids from list_transcript_flags)' establishes the required prior step, and the description clarifies that replacement text only applies to accepted name fixes. It does not explicitly exclude alternatives or say when to skip this tool in favor of add_transcript_correction, so it falls short of full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
revoke_media_linkRevoke share linksADestructiveIdempotent
Turn share links off now: one (linkId), a clip's (clipId), a project's (projectId) or all of yours (all: true). Give exactly one. Returns { revoked, message }. Anyone holding a revoked link gets a 404 from then on.
| Name | Required | Description | Default |
|---|---|---|---|
| all | No | Every share link you have | |
| clipId | No | Every link to this clip | |
| linkId | No | Link id (from get_media_links or list_media_links) | |
| projectId | No | Every link to this project's clips and zip |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as destructive and idempotent. The description adds valuable consequence detail: revoked links return 404 afterward, and it discloses the return shape { revoked, message }. It does not mention permissions or whether links can be re-enabled, but the key behavioral effect is explicit.
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 core action, followed by scopes, invocation constraint, return shape, and consequence in a compact form. Every sentence carries useful 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?
Covers what the tool does, valid scope combinations, return value, and post-revocation behavior. Despite no output schema, the return shape is stated, and annotations already carry the safety profile.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds important mutual-exclusivity semantics ('Give exactly one') and maps each parameter to its revocation scope, which the schema alone does not fully emphasize.
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 ('Turn share links off') and enumerates the four supported scopes. An agent can immediately tell this is a revocation tool rather than a listing or creation tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly instructs to 'Give exactly one' scope, which prevents invalid multi-scope calls. It implies use when a share link must be disabled but does not explicitly contrast with sibling tools beyond noting linkId comes from get_media_links or list_media_links in the schema.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rotate_webhook_secretRotate webhook secretADestructive
A new signing secret for a webhook. Deliveries are signed with both the new and the old one for 24 h, so the receiver can switch; refused while a rotation is still open. Returns { secret, previousStopsAt, message }.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Webhook id (from list_webhooks) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotation only says destructiveHint=true; the description adds real substance beyond that by disclosing the 24-hour dual-signing grace period so receivers can switch, the refusal condition for overlapping rotations, and the exact response shape including previousStopsAt. The only gap is the absence of any permission or permanence statement about what happens to the old secret after the window closes.
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, front-loaded with the outcome, then the behavioral caveat, then the return shape; no filler. The first sentence is a noun fragment rather than a verb phrase, which slightly weakens the opening but costs no length.
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 no output schema, the description covers the essential behavioral contract: grace period, refusal condition, and returned fields. It is close to complete; only authorization requirements and post-window invalidation of the old secret are left unstated.
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, and the schema already explains that it is the webhook id sourced from list_webhooks. The description adds nothing further about the id, which is acceptable given the schema does the work — the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies the exact resource and outcome: a new signing secret is generated for a webhook, and it explains the dual-signing window that makes this a rotation rather than a plain read. It is missing an explicit verb in the opening fragment, but combined with the name/title the action is unambiguous and clearly distinct from update_webhook or create_webhook.
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 supplies one concrete precondition — the call is 'refused while a rotation is still open' — which tells the agent when the tool will fail. However, it never states when an agent should rotate versus simply updating the webhook, nor does it name update_webhook as the alternative, so the routing guidance is implied rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
save_layer_templateSave layer templateA
Create a template from exactly one of clipId (that clip's layers: spanning = fill, touching the start = head, touching the end = tail, else anchored to the nearer edge; plus the intro and outro the clip renders with) or layers (each with a timing, see list_layer_templates; [] with bumpers = an intro / outro only template). Returns the template { id, name, layerCount, layers, bumpers }. Use apply_layer_template to put it on clips
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Template name (1-120 chars) | |
| clipId | No | Build the template from this clip's layers (get_project or search_clips). Pass clipId or layers, not both | |
| layers | No | Or the layers themselves, each with a timing: { kind: asset|text|audio, id, timing: { mode: head|tail|fill|relative, start, end, minSec, maxSec }, ...the layer's own fields (assetId, x, y, w / text, size, color / volume, duck, fade, loop) } | |
| bumpers | No | With layers: the intro / outro the template puts on clips ({ intro, introSec, outro, outroSec }; a slot left out = clips keep their own, null = none, an id = that video or image). With clipId the clip's intro and outro are saved too |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does well: it explains how clipId layers are translated into timing modes (spanning=fill, touching start=head, touching end=tail, else nearest edge), that intro/outro rendered with the clip are saved too, and the returned object shape. It omits any notes on permissions or limits, but discloses core behavior beyond the schema.
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 primary action and the exclusive-or constraint, then edge cases, then the return shape and the sibling hand-off. It is dense and 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 tool with deeply nested layer schemas and no output schema, the description supplies the return shape { id, name, layerCount, layers, bumpers } and the clipId translation rules. Cross-references to list_layer_templates, list_bumpers, and search_assets cover the remaining lookup steps.
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: the clipId-to-timing-mode mapping rules are not derivable from the schema, and the empty-layers-plus-bumpers case is a semantic edge case. Bumpers wording largely repeats the schema's own description.
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 ("Create a template") and immediately names the two mutually exclusive sources (clipId vs layers). It is easy to distinguish from siblings like apply_layer_template, list_layer_templates, and update_layer_template.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit routing ("Use apply_layer_template to put it on clips") and clarifies the exclusive-or between clipId and layers, plus the edge case of [] with bumpers for an intro/outro-only template. It does not explicitly contrast with update_layer_template, so it stops just 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.
search_assetsSearch library, catalog and providersARead-only
Find assets. source "library" = your own uploads (name and tags; empty q lists all); omitted or "catalog" = the Reelsaw catalog (CC0, works offline); or a provider an admin enabled. Returns { provider, items: [{ provider, externalId, name, kind, license, durationSec }], nextCursor }. Adds nothing: a catalog / provider hit's provider + externalId go to add_asset.
| Name | Required | Description | Default |
|---|---|---|---|
| q | No | What to look for, e.g. "whoosh", "arrow", "city at night"; empty lists everything in the source | |
| kind | No | Only this kind of result | |
| limit | No | Results per page (1-60, default 24) | |
| cursor | No | nextCursor from the previous page; omit for the first page | |
| source | No | library, catalog (default), pexels, pixabay, freesound, iconify, openverse, giphy or klipy | |
| deleted | No | library only: list your deleted items instead (their ids go to restore_asset) | |
| license | No | freesound only: cc0 (default) or by (CC0 and CC-BY, attribution is stored) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is covered; the description adds real value with the return shape (provider, items, nextCursor), the offline/catalog behavior, and the fact that this tool adds nothing itself. It stops short of disclosing auth requirements or provider-enablement nuance, but it is well beyond the annotation baseline.
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: purpose first, then source semantics, then return shape, then the add_asset handoff. It is slightly telegraphic ('Adds nothing', parentheticals) and could be marginally smoother, but nearly 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 7-param, read-only search tool with no output schema, the description supplies the return envelope and pagination token, covers all source modes, and links to the downstream add_asset call. Remaining gaps (kind/limit filtering details, license attribution nuance) are covered by the rich schema, so the description is essentially complete for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds semantics the schema does not, notably source default behavior, the library name-and-tag matching scope, offline catalog behavior, and the role of provider + externalId in add_asset. The deleted and license params are only lightly touched, but the core source semantics are clarified.
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 ('Find assets') and immediately distinguishes three source modes (own uploads, catalog, admin-enabled provider) plus the terminal action of routing hits to add_asset. An agent can tell this apart from add_asset and unrelated siblings 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?
Explicitly defines when each source applies: library = own uploads, omitted/'catalog' = Reelsaw catalog (CC0, works offline), otherwise an admin-enabled provider. It also states the follow-up path ('a catalog / provider hit's provider + externalId go to add_asset'), removing ambiguity about the search-then-add workflow.
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 (search_assets with source library), or null for no default |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With only idempotentHint in annotations, the description carries real weight and delivers: the forward-looking scope of the change, the fact that existing projects are unaffected, the clearing behavior, and the return shape { ok }. It doesn't cover permission/auth requirements or confirm whether setting a default replaces any prior default, so it stops short of fully describing side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight clauses: what it does, the scope caveat, and the alternative tool, all front-loaded with zero filler. The return note is one token and 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-param, non-destructive default-setting tool with a fully documented schema, the description covers scope, clearing, the sibling alternative, and the return value. 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% — slot's enum and assetId's null branch are both documented in the schema, including the search_assets hint. The description's 'assetId null clears it' only restates the schema, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (set default), resource (library item as intro/outro) and an explicit scope (projects created from now on), which cleanly separates it from set_project_bumpers. An agent can distinguish this from the per-project variant 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?
Explicitly names when this applies ('projects you create from now on') and when it does not ('existing projects keep theirs'), then routes the alternative case to set_project_bumpers. The null case for clearing is also stated inline.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_email_preferencesSet email preferencesAIdempotent
Turn topics of optional email on or off; omitted topics stay as they are. ready = the note sent when projects finish while you are away (Settings → Account, or the link in the email). Mail you need (password reset, verification) is not affected. Returns { ok, emailPreferences }.
| Name | Required | Description | Default |
|---|---|---|---|
| ready | No | the note sent when projects finish while you are away: true to get it, false to stop it |
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 does add real behavior: partial-update semantics ('omitted topics stay as they are') and a scope boundary that essential mail (password reset, verification) is unaffected. It also discloses the return shape, which no output schema provides; the main gap is that it doesn't say how to discover which optional topics 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?
Front-loaded with the core action and the partial-update rule, and every clause (ready meaning, unaffected essential mail, return shape) carries information. The parenthetical about Settings → Account is slightly tangential and the sentence fragments make it a bit choppy, but 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?
For a one-parameter, idempotent mutation with no output schema, the description covers what changes, what is preserved, what is out of scope, and the return shape — enough to call it correctly. The remaining hole is discoverability of topics and the read counterpart, which the description never mentions.
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% for the single parameter, and the description's 'ready = the note sent when projects finish while you are away' essentially restates the schema's own definition rather than adding new meaning. With one well-documented parameter, baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource: turning optional-email topics on or off, with a clear scope restriction that only optional mail is touched. It never names the sibling get_email_preferences, so the read/write pairing with that tool must be inferred from the name alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: call it to toggle a topic, and omitted topics are left untouched (useful partial-update guidance). It offers no explicit when-to-use or when-not guidance and never points at get_email_preferences for reading current state, though the Settings → Account remark hints at where this is surfaced.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_instance_settingsChange instance settingsADestructiveIdempotent
Admins only: change instance settings without a restart; every process applies them within seconds and the change is audited. Pass only the keys to change; null returns a key to the environment's value; an empty string clears an optional one (URLs, captcha). Validated as a whole (a captcha provider needs both keys; email verification needs an email driver). Returns the same state as get_instance_settings.
| Name | Required | Description | Default |
|---|---|---|---|
| TERMS_URL | No | Terms of service link shown on the sign-up form; empty = none. | |
| CATALOG_URL | No | Where the Reelsaw catalog manifest (sounds, icons, stickers) is fetched from, hourly; the starter pack bundled with Reelsaw is used until a newer one arrives. | |
| PRIVACY_URL | No | Privacy policy link shown on the sign-up form; empty = none. | |
| SIGNUP_MODE | No | Who may sign up: open (anyone, right for a public instance with email confirmation), approval (new accounts wait for an admin; a private box) or closed (nobody). The first account is always the admin. | |
| UPDATE_CHECK | No | Ask GitHub for the latest release and tell admins when a newer Reelsaw exists. Only the request leaves the machine. | |
| GIPHY_API_KEY | No | Giphy API key: enables GIFs and stickers in Browse. Stored encrypted; empty = provider hidden. | |
| KLIPY_API_KEY | No | Klipy API key: enables GIF search in Browse (experimental). Stored encrypted; empty = provider hidden. | |
| MAX_UPLOAD_MB | No | Largest accepted file upload, in MB. | |
| REFINE_SCENES | No | Scan the video for on-screen text (burned-in captions, watermarks, slides) during refine. On by default; off closes the ceiling (projects opt out via refineScenes). Shot cuts are always detected. | |
| STALL_MINUTES | No | A running job with no progress for this long is reported as stalled (log and UI). | |
| DISFLUENCY_LLM | No | Model pass on top of rule-based disfluency detection. Off by default. Ignored when disfluency removal is off. Turn on so projects may opt in via disfluencyLlm. | |
| HEALTH_DETAILS | No | Include machine numbers in GET /api/health for anonymous callers (private networks only). Admins always get them. | |
| MAX_STORAGE_MB | No | MB of sources, uploads, renders and intros/outros an account may keep (deleted items count until they are deleted forever). 0 = unlimited. | |
| PEXELS_API_KEY | No | Pexels API key (free): enables stock photos and portrait videos in Browse. Stored encrypted; empty = provider hidden. | |
| WATERMARK_TEXT | No | The watermark text, e.g. your site name. | |
| ICONIFY_API_URL | No | Iconify API used for icon search; the public one by default, or your own self-hosted instance (https). | |
| PIXABAY_API_KEY | No | Pixabay API key (free): enables photos, illustrations, vectors and videos in Browse. Stored encrypted; empty = provider hidden. | |
| CAPTCHA_PROVIDER | No | Bot protection on sign-up, sign-in and password reset: cloudflare-turnstile, google-recaptcha or hcaptcha; empty = off. Needs both keys. | |
| CAPTCHA_SITE_KEY | No | Public captcha key the browser widget uses; empty = unset. | |
| FREESOUND_API_KEY | No | Freesound API key (free): enables sound effects in Browse. Stored encrypted; empty = provider hidden. | |
| OPENVERSE_ENABLED | No | Show Openverse (Creative Commons images and audio, no key) in Browse. Off by default until you have checked its limits for your use. | |
| CAPTCHA_SECRET_KEY | No | Secret captcha key the server verifies with; stored encrypted, never shown again; empty = unset. | |
| DISFLUENCY_REMOVAL | No | Detect fillers, repetitions and false starts after transcription. Off by default; turn on so projects may opt in via refineDisfluency. | |
| MAX_SOURCE_FILE_MB | No | Largest file a link source may download (yt-dlp --max-filesize), in MB. | |
| CLIP_RETENTION_DAYS | No | Delete rendered clip files this many days after rendering; the clip stays and can be re-rendered. 0 = keep forever. | |
| MEDIA_LINK_TTL_DAYS | No | Share links last this many days unless the owner picks less. | |
| SCRATCH_CACHE_HOURS | No | With an S3 store, drop a worker's local copies of the sources and rendered clips of finished projects after this many idle hours; a job pulls them back from the bucket when it needs them, and a worker short of disk drops the least recently used ones first. 0 = keep them on the worker. The local store needs nothing: scratch and store are the same file. | |
| STEP_RETENTION_DAYS | No | Drop the saved checkpoints (finding-moments windows) of a finished project this many days after it last changed; a Retry sooner than that reuses them. 0 = keep forever. | |
| EVENT_RETENTION_DAYS | No | Prune project events older than this; each project keeps its run skeleton. 0 = keep forever. | |
| WATERMARK_NON_ADMINS | No | Burn a small watermark into the clips of accounts that are not admins. A paid plan removes it, and an admin can switch it per user on the Users page. | |
| MAX_PROJECTS_PER_USER | No | Projects an account may keep. 0 = unlimited. Admins can override per user on the Users page. | |
| MAX_REQUESTS_PER_HOUR | No | Changes an account may make per hour. 0 = unlimited. | |
| MAX_WEBHOOKS_PER_USER | No | Webhook endpoints an account may add. 0 = unlimited. Admins can override per user on the Users page. | |
| SOURCE_RETENTION_DAYS | No | Delete stored source videos this many days after upload; the project stays and Retry re-fetches. 0 = keep forever. | |
| TRANSCRIPT_CORRECTION | No | After transcription, fix misheard names with the language model. On by default; off closes the ceiling so no project runs it (projects opt out via refineEntities). | |
| DELETED_RETENTION_DAYS | No | Deleted projects and replaced clips stay restorable this long, then rows and files go. 0 = keep forever. | |
| MAX_LIVE_JOBS_PER_USER | No | Queued plus running jobs an account's own requests may add to. 0 = unlimited. | |
| MAX_RERENDERS_PER_HOUR | No | Re-renders, hand-made clips and re-runs (re-analyze, refine) an account may ask for per hour. 0 = unlimited. | |
| MEDIA_LINK_ALLOW_NEVER | No | Owners may make a share link that never expires (they can still revoke it). | |
| BLOCK_DISPOSABLE_EMAILS | No | Refuse sign-ups from known temporary-address domains (a vendored list of about 120k domains). | |
| DECISION_RETENTION_DAYS | No | Prune users' recorded decisions (accepts, rejects, edits Reelsaw learns from) older than this. They outlive deleted projects until then. 0 = keep forever. | |
| MAX_REQUESTS_PER_MINUTE | No | Changes (API mutations, MCP tool calls) an account may make per minute. 0 = unlimited. Admins can override per user on the Users page. | |
| LLM_CALL_TIMEOUT_SECONDS | No | Longest one model call may take (all its HTTP attempts together) before its step is stopped and retried. 0 = auto: 120 s for a hosted model, 600 s for a self-hosted one, and for a self-hosted transcription at least twice the chunk's audio length. Time spent waiting for a provider slot does not count. A slow CPU-only model may need more. | |
| LLM_USAGE_RETENTION_DAYS | No | Prune model and transcription usage rows older than this. 0 = keep forever. | |
| ALLOW_PRIVATE_SOURCE_URLS | No | Let link sources point at LAN or loopback hosts (a NAS). Off, they are blocked (SSRF guard). | |
| MAX_NEW_PROJECTS_PER_HOUR | No | Projects an account may create per hour. 0 = unlimited. | |
| MEDIA_LINK_RETENTION_DAYS | No | Delete revoked and expired share links this many days after they stopped working. 0 = keep forever. | |
| ADMIN_EVENT_RETENTION_DAYS | No | Prune the admin event log after this many days. 0 = keep forever. | |
| ALLOW_PRIVATE_WEBHOOK_URLS | No | Let webhook URLs point at LAN or loopback hosts (a self-hosted n8n next to Reelsaw), over http too. Off, they must be public https (SSRF guard). | |
| MAX_SIGNUPS_PER_IP_PER_DAY | No | Accounts one network address may create per day. 0 = unlimited. Needs TRUST_PROXY behind a reverse proxy. | |
| MAX_SOURCE_MINUTES_PER_DAY | No | Minutes of source video an account may add per day (UTC). 0 = unlimited. | |
| REQUIRE_EMAIL_VERIFICATION | No | New users must click the verification link before they can sign in. The link works for 24 hours and is single-use; an expired one offers a new send. Needs an email driver in .env. | |
| STAGE_IDLE_TIMEOUT_MINUTES | No | A stage made of checkpointed steps (finding moments) is stopped when no step has finished for this long; Retry continues where it stopped. 0 = auto: 1.5 times the model call timeout. | |
| MAX_SOURCE_MINUTES_PER_MONTH | No | Minutes of source video an account may add per period: its billing period when it has a plan, else the calendar month (UTC). 0 = unlimited. | |
| WEBHOOK_DELIVERY_RETENTION_DAYS | No | Delete webhook delivery log rows older than this. 0 = keep forever. | |
| EVENT_PROJECT_DONE_READY_EMAIL_DELAY_MINUTES | No | Minutes to wait after the first project in a batch finishes before emailing that the clips are ready, so several projects land in one note. Sent only when an email driver is set and the account has not come back since those projects finished. A project that finishes while a note is already waiting joins that note. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing that changes take effect within seconds across processes without a restart, that the change is audited, and that validation happens as a whole so one bad key rejects the batch. It does not explain the destructiveHint=true consequence (e.g. that clearing a URL or key silently disables a feature) or whether a rejected batch leaves any state changed, and no rollback path is described.
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?
Roughly sixty words across four front-loaded sentences: permissions and effect first, then the update convention, then validation rules, then return shape. No sentence is redundant with the schema and nothing is buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 56 parameters and no output schema, the description handles the cross-cutting semantics well and points to get_instance_settings for the returned state. However, for a destructive, audited bulk mutation it omits what an agent most needs at this complexity: whether a failed whole-batch validation changes nothing, and whether there is any way to revert an accidental reset to defaults.
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 already 100%, so the per-key meanings are documented. The description still adds real meaning the schema cannot: the tri-state convention (omit / null / empty string) and cross-field validation constraints such as a captcha provider needing both keys and email verification needing an email driver.
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 ('change instance settings') plus scope ('Admins only') and effect ('without a restart'). It also names the sibling get_instance_settings as the read counterpart whose state is returned, so an agent can tell the pair apart 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 invocation rules: pass only the keys to change, use null to reset to the environment value, use an empty string to clear optional values. It does not explicitly exclude per-user settings handled by siblings such as set_email_preferences or set_learning, so the when-not guidance is implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_learningTurn learning on or offAIdempotent
Whether Reelsaw records your decisions (accepts, rejects, cuts, clip edits) to learn from (Settings → Learning, on by default). Off stops recording; what is already kept stays until forget_decisions. Returns { enabled }.
| Name | Required | Description | Default |
|---|---|---|---|
| enabled | Yes | true records decisions, false stops |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the lone idempotentHint annotation: discloses the default ('on by default'), the exact scope of what is recorded (accepts, rejects, cuts, clip edits), the fact that disabling is non-destructive, and the retention rule until forget_decisions. The return shape is also given. Missing only auth/permission notes, 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?
Three short clauses, front-loaded with the state semantics before the retention caveat and the return shape. Slightly fragmentary opening, but no sentence is wasted.
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-boolean, idempotent settings toggle this covers everything an agent needs: default state, effect of each value, data-retention consequence, the relevant alternative tool, and the response shape. Nothing material is left to guess.
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 boolean is already documented, so the baseline is 3; the description earns a step up by enumerating the decision types that get recorded and clarifying that 'off' merely stops new recording rather than deleting anything.
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 the resource (Reelsaw decision recording / Learning setting) and the effect of both states, so an agent can tell it apart from the nearby forget_decisions and list_decisions siblings. It is phrased as a fragment ('Whether Reelsaw records...') rather than a verb+object statement, which costs a bit of crispness but not comprehension.
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 the consequence of each state ('Off stops recording') and points to the sibling to use for actually removing data ('stays until forget_decisions'), which is a real routing decision. It does not spell out an explicit when-to-use trigger, but the toggle semantics make the selection obvious.
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.
set_project_defaultsSet project defaultsAIdempotent
Replace the settings every new project starts with; existing projects keep theirs. Send the whole set you want: keys left out are cleared, {} clears all (read get_project_defaults first). Intro and outro change through set_default_bumper. Returns { ok, projectDefaults, hint }.
| Name | Required | Description | Default |
|---|---|---|---|
| defaults | Yes | The complete set of defaults, e.g. { language: "en", maxClips: 5, pauses: "tight" } |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the idempotent annotation, the description discloses the destructive replacement semantics: omitted keys are cleared, {} clears all, and existing projects are unaffected. It also names the return shape ({ ok, projectDefaults, hint }), which is valuable with no output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences front-load the replacement behavior, then cover clearing semantics, a prerequisite, an alternative tool, and the return value with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single nested-object parameter with full schema documentation and no output schema, the description supplies the missing replacement semantics, prerequisite, sibling routing, and return shape. Nothing essential for correct invocation is omitted.
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 nested property definitions already explain individual setting keys. The description adds the crucial whole-object replacement rule ('Send the whole set you want: keys left out are cleared, {} clears all'), which the schema does not make explicit, though it does not discuss every parameter individually.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Replace the settings every new project starts with') and immediately scopes it: existing projects keep theirs. It distinguishes this tool from the closely related get_project_defaults and set_default_bumper by name.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says to read get_project_defaults first, explains that intro and outro belong to set_default_bumper, and clarifies the alternative behavior for existing projects. That is direct when-to-use and when-not-to-use guidance rather than implied context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_project_source_textSet source text handlingAIdempotent
Hide or keep text burned into the source video (captions, logos) for the whole project: hide covers it, keep leaves it, always shows it. Re-renders every finished clip so the set agrees. Returns { changed, needsRerender, rerendered, skipped, hint }; rerendered is how many clips were queued, so follow with wait_for_project; skipped clips were still preparing or rendering and need rerender_clips once done (needsRerender is true).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| sourceText | Yes | hide = cover on-screen text in the source, keep = leave it, always = always show it |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare idempotency, yet the description discloses the key side effect (re-renders every finished clip) and the meaning of each return field (changed, needsRerender, rerendered, skipped), plus the skipped-clip edge case and remediation. This is disclosure well 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?
Single dense paragraph that front-loads the action and mode semantics before the return-value explanation. Efficient, though slightly crowded by packing enum restatement and return fields together.
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 explains the returned object's fields and next steps, covering everything an agent needs to call and correctly follow up on this mutation. Complete for a 2-param idempotent setter.
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 enum is documented in-schema, so the description doesn't need to repeat it, but it reinforces the three mode meanings ('hide covers it, keep leaves it, always shows it') in workflow terms. Marginal added value over an already-complete 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 specific verb ('Hide or keep') and resource ('text burned into the source video') scoped to 'the whole project', with the enum behaviors spelled out. An agent can distinguish this from clip-level or rendering siblings 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?
Explains the three modes and, importantly, tells the agent to follow with wait_for_project and to call rerender_clips once skipped clips finish. It lacks an explicit when-not-to-use statement versus rerender_clips/apply_framing, but the follow-up routing is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
test_webhookTest webhookA
Send a webhook.test delivery now and wait for the answer. Returns { ok, code, message, response (first 2 KB of what the receiver said) }.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Webhook id (from list_webhooks) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Without annotations, the description carries the full behavioral burden. It usefully discloses that the call waits for a response and returns ok, code, message, and the first 2 KB of the receiver response, but it omits timeout behavior, external side effects, and permission requirements.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences with the action front-loaded and the return shape immediately following. There is no redundant or filler text.
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 one-parameter test tool with no output schema, the description is largely complete: it explains the action, the blocking wait, and the returned fields. Minor gaps remain around failure/timeout behavior and side effects.
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 parameter is fully documented in the schema as coming from list_webhooks. The description adds no parameter details beyond that, 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: send a webhook.test delivery and wait for the answer. It is clearly a webhook-testing tool, though it does not explicitly contrast with the sibling resend_webhook_delivery.
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 word "test" and "now" imply this is for verifying a webhook endpoint, but the description gives no explicit when-to-use guidance, prerequisites, or alternatives. Usage is understandable but left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_assetUpdate library assetAIdempotent
Rename one of your own library items, replace its tags, or change how long a still image shows (deleted items too; shared catalog and provider items cannot be changed). Only labels change; nothing re-renders, except that a new image length applies on each project's next render. Returns { id, name, tags, durationSec, previousName }.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | New name (1-120 chars) | |
| tags | No | Replaces the tags (lowercase words; max 20); [] clears them | |
| assetId | Yes | Library asset id (from search_assets) | |
| imageSeconds | No | Seconds a still image shows as an intro/outro (1-10); images only |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the idempotentHint annotation, the description discloses the limited mutation surface: only labels change and nothing re-renders except image duration on the next render. It also states scope exclusions and specifies the return shape, giving the agent a strong behavioral picture.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: it names the operations, states scope constraints, explains render behavior, and gives the return shape without wasted prose.
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?
Although there is no output schema, the description supplies the return fields. Combined with the rich input schema and clear scope/side-effect disclosure, it is complete enough for an agent to invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents name, tags, assetId, and imageSeconds in detail. The description adds conceptual mapping for the operations and some behavioral context, but does not add syntax or format detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states specific operations (rename, replace tags, change still-image duration) on a clearly identified resource (own library items). It also distinguishes editable assets from shared catalog/provider items, which siblings like add_asset or delete_asset do not address.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear scope: own library items can be updated, deleted items can be updated, but shared catalog and provider items cannot. It does not explicitly name sibling alternatives such as search_assets for finding IDs or delete_asset for removal, so it falls 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.
update_clipUpdate clipA
Edit one clip (3 s-10 min): only the fields you pass change; style, layoutSections and layers replace the whole value (null = project's / none). Title, caption and hashtags apply at once; bounds, hook, framing, style, emphasis, layers and intro/outro are burned in and re-render (~1 min) unless rerender is false. Returns the clip summary plus { changed, needsRerender, rerendered, hint }; 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 | |
| layers | No | Everything laid over or played under the clip, one list (max 30): kind asset = a library image/GIF/video (search_assets with source library; logos, stickers, b-roll), kind text = a line of text, kind audio = music or a sound effect (a library audio asset with a window in source seconds, volume, ducking, fade, loop). Replaces the whole list; null or [] = none. get_clip returns it | |
| 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, same as the app); 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 burden and does: it discloses destructive replacement semantics for three fields, the ~1 min per-field render cost, which fields are burned in vs applied instantly, and the async completion protocol (poll get_clip). It even states the return payload. Nothing material about side effects or timing is left hidden.
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 dense clauses, each doing distinct work — scope, merge/replace rules, render cost, return protocol — with the most actionable constraint (partial update) front-loaded. Zero 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 13-parameter mutation with no annotations and no output schema, the description covers update semantics, side-effect cost, the deferred-render escape hatch, and the exact return shape plus polling instruction. An agent could invoke it correctly without opening the schema for semantics.
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 earns above that by adding semantics the schema cannot express: the instant-vs-burned-in partition of fields, null meaning 'follow the project'/none, and the fact that emphasis/layers replace rather than merge.
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+resource ('Edit one clip') plus a hard scope constraint (3 s–10 min), which immediately separates it from create_clip, delete_clip and rerender_clip. It never explicitly names a sibling it is not, so the differentiation is inferred rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear operating context: partial-update semantics ('only the fields you pass change'), the replacement rule for style/layoutSections/layers, and the rerender:false path that defers work to rerender_clip. It stops short of an explicit 'don't use this when…' exclusion or a named alternative for non-clip editing (update_project).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_layer_templateUpdate layer templateAIdempotent
Rename a layer template, replace its layers (the whole list, each with a timing) and/or replace its intro / outro (bumpers; null = it sets neither); a field left out is untouched. Clips that already got the template keep what they have; apply_layer_template again to refresh them. Returns the template.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Template name (1-120 chars) | |
| layers | No | The template's layers, each with a timing (max 30) | |
| bumpers | No | ||
| templateId | Yes | Layer template id (list_layer_templates) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the idempotent annotation, the description discloses important mutation semantics: omitted fields are untouched, layers are replaced as a whole list, bumpers use null to mean neither intro nor outro, and existing clips retain their current template until re-applied. It also states the return value.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded, covering update behavior, propagation effects, and return value without redundant restatement. Every sentence adds operational meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complex nested schema, the description sufficiently explains the update model, replacement semantics, clip-refresh behavior, and return value. It does not cover every nested layer field, but those are well documented in the schema and do not need to be repeated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 75% description coverage, and the description adds meaningful semantics beyond field-level schema text: whole-list replacement for layers, partial-update behavior for omitted fields, and null-vs-omitted behavior for bumpers. It does not fully restate all nested layer properties, but the schema already covers those in 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?
The description uses a specific verb/resource pair ('Rename a layer template') and enumerates the exact updateable aspects: name, layers, and bumpers. It also distinguishes this from applying a template by explaining that existing clips are not refreshed unless apply_layer_template is called again.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes clear this is a partial update of an existing layer template, with omitted fields untouched and layers treated as a whole-list replacement. It also gives clear follow-up guidance for refreshing already-applied clips, though it does not explicitly compare against save_layer_template or other sibling update paths.
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, refineEntities, refineDisfluency, disfluencyLlm, refineScenes); only the fields you pass change. Does not re-pick clips or re-render: reanalyze_project picks again with the new selection settings, refine_project re-runs refine steps, rerender_clips applies style changes. Returns { changed, needsReanalyze, needsRefine, 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 | |
| metadata | No | Replace the project's metadata (the whole map; {} clears it) | |
| 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?
With only idempotentHint=true in annotations, the description carries most of the burden and does well: it discloses partial-update semantics, that no clips are re-picked or re-rendered, and the exact return shape including the needsReanalyze/needsRefine/needsRerender follow-up flags — valuable since no output schema exists. It omits permissions/auth and what happens on invalid or conflicting values (e.g. maxClipSeconds below minClipSeconds).
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 the merge rule, followed by the sibling routing and return shape — good ordering. The long settings enumeration in the first sentence partially duplicates the schema and is the one part that does not fully earn its space.
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 deeply nested settings object and no output schema, the description supplies the two things an agent most needs: the merge semantics and the downstream-action flags. Minor gaps remain around validation errors and the bumpers/clear/metadata paths, which are only covered in the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with rich per-field descriptions, so the baseline is 3. The description's parenthetical list of settings mirrors what the schema already documents and does not mention the 'clear' or 'metadata' parameters, so it adds little beyond structured data.
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 pair ('rename a project and/or change its saved settings') and enumerates the settings domains covered. An agent can distinguish it from update_project_style, set_project_bumpers, and update_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 states the key constraint ('only the fields you pass change') and draws hard boundaries against three named alternatives: reanalyze_project for re-picking, refine_project for refine steps, rerender_clips for applying style. That is when-to-use and when-not-to-use in two sentences.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_project_styleUpdate project styleADestructiveIdempotent
Change the caption/hook look for the whole project (font, colors, size, position, words per line). Clears per-clip style overrides unless keepOverrides, and re-renders every finished clip unless rerender is false. Returns { changed, needsRerender, rerendered, skipped, hint }; rerendered is how many clips were queued, skipped how many were still preparing or rendering (they need rerender_clips once done). For one clip use update_clip { style }.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| style | Yes | The style fields to change; fields left out keep their value | |
| rerender | No | Re-render finished clips now (default true); false saves the style and the next render shows it | |
| keepOverrides | No | Keep clips' own style overrides instead of clearing them (default false) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true and idempotentHint=true, and the description concretizes the destruction: per-clip style overrides are cleared unless keepOverrides is set, and every finished clip is re-rendered unless rerender is false. It also discloses the return payload semantics (changed, needsRerender, rerendered, skipped) and the follow-up action for skipped clips, going well beyond the annotation flags.
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 core action and scope, then side effects, then return shape, then sibling routing – a logical order with no filler. The opening sentence is dense with parenthetical examples, which is efficient but slightly heavy; nothing is redundant, however.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, nested-object mutation with no output schema, the description covers the side effects, the shape and meaning of the return object, and the follow-up path for skipped clips. An agent has everything needed to invoke it correctly and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 by explaining the consequence of rerender=false (style saved, applied on next render) and the difference between rerendered and skipped counts. The keepOverrides consequence (preserving per-clip overrides) is also spelled out rather than merely labeled.
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 ("Change the caption/hook look for the whole project") and enumerates the dimensions affected (font, colors, size, position, words per line). It explicitly scopes the operation to the whole project and names the sibling tool to use for a single clip, so it is distinguishable from update_clip at a glance.
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 final sentence routes the agent to update_clip { style } for one-clip changes, and the description explains what happens to clips that are still preparing or rendering (they need rerender_clips once done). It gives clear context but does not state prerequisites or when-not-to-use conditions beyond the single-clip case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_webhookUpdate webhookAIdempotent
Change a webhook's url, events or description, or turn it on or off (enabled). Turning it on clears a failure streak; turning it off cancels deliveries waiting to be sent (resend_webhook_delivery brings them back). Returns { endpoint, changed, message }.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Webhook id (from list_webhooks) | |
| url | No | New URL to POST to (https) | |
| events | No | Replace the events it gets | |
| enabled | No | Turn it on (true) or off (false) | |
| description | No | New label; null clears it |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare idempotentHint, so the description carries the real burden and does so well: enabling clears a failure streak, disabling cancels in-flight deliveries, and the recovery path is named. It also discloses the return shape { endpoint, changed, message }, which no output schema provides.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the mutable surface, then the side effects, then the return shape. Every clause earns its place; no restatement of the name or title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description supplies the return shape and the destructive side effect of disabling, which is the highest-risk thing an agent could do here. Nothing needed to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3, but the description adds semantics the schema does not: 'enabled' has the side effect of clearing a failure streak, and events is a replace rather than a merge. The null-clears-it behavior for description is already in the schema, so no extra credit there.
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 (change/update) and resource (webhook) and enumerates exactly which fields are mutable: url, events, description, enabled. That field-level enumeration distinguishes it cleanly from create_webhook, delete_webhook, and rotate_webhook_secret without needing to name them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Makes clear this is the partial-update path and routes the agent to resend_webhook_delivery for restoring canceled deliveries, which is genuine when-to-use guidance. It stops short of explicit when-not guidance (e.g., use create_webhook to add a new endpoint, use test_webhook to verify), so it lands just below the top.
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, stageDetail ({ done, total, etaSec } while a stage works in parts, else null), 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?
Goes well beyond the readOnlyHint annotation by disclosing that the call blocks, what the timeout produces, and how to continue after a timeout. It also enumerates the return payload including stageProgress semantics ("else null") and the partial-stage etaSec, which is real behavioral context an agent cannot get from annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the blocking behavior and the timeout escape hatch before the return shape. The dense parenthetical type listing for stageDetail is slightly harder to parse than prose or a shallow field list, 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?
No output schema exists, so the description carries the return-value burden and does so thoroughly (id, status, stage, stageProgress, stageDetail, error, clips). For a two-parameter long-poll read tool, nothing needed to invoke or interpret it 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 documents both id (source: create_project/list_projects) and timeoutSeconds (1-120, default 60). The description only alludes to timeoutSeconds passing, adding no syntax or semantics beyond the schema, so the baseline 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 plus the blocking scope: "Block until the project is done or failed, or timeoutSeconds pass." It also names the contrasting sibling (get_project) so an agent can distinguish blocking vs non-blocking reads immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when/when-not guidance: use this to wait, use get_project "instead for a non-blocking look with full clip details." It even covers the post-timeout path — "on timeout the same with hint 'Still running': call it again" — leaving no retry inference to the agent.
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.
3 tool updates
v0.32.0- Added
get_email_preferences - Added
set_email_preferences - Changed
set_instance_settings1 field changed- added
Input schema / properties / EVENT_PROJECT_DONE_READY_EMAIL_DELAY_MINUTESAdded value: +{ + "anyOf": [ + { + "maximum": 180, + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Minutes to wait after the first project in a batch finishes before emailing that the clips are ready, so several projects land in one note. Sent only when an email driver is set and the account has not come back since those projects finished. A project that finishes while a note is already waiting joins that note." +}
14 tool updates
v0.31.0- Changed
create_project1 field changed- added
Input schema / properties / metadataAdded value: +{ + "additionalProperties": { + "maxLength": 500, + "type": "string" + }, + "description": "Your own key/value strings (≤20 keys, 1 KB), returned by get_project and sent in every webhook for this project, e.g. { runId: \"n8n-123\" }", + "propertyNames": { + "pattern": "^[A-Za-z0-9_.-]{1,40}$", + "type": "string" + }, + "type": "object" +}
- Added
create_webhook - Added
delete_webhook - Added
get_media_links - Added
list_media_links - Added
list_webhook_deliveries - Added
list_webhooks - Added
resend_webhook_delivery - Added
revoke_media_link - Added
rotate_webhook_secret - Changed
set_instance_settings6 fields changed- added
Input schema / properties / ALLOW_PRIVATE_WEBHOOK_URLSAdded value: +{ + "description": "Let webhook URLs point at LAN or loopback hosts (a self-hosted n8n next to Reelsaw), over http too. Off, they must be public https (SSRF guard).", + "type": [ + "boolean", + "null" + ] +} - added
Input schema / properties / MAX_WEBHOOKS_PER_USERAdded value: +{ + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Webhook endpoints an account may add. 0 = unlimited. Admins can override per user on the Users page." +} - added
Input schema / properties / MEDIA_LINK_ALLOW_NEVERAdded value: +{ + "description": "Owners may make a share link that never expires (they can still revoke it).", + "type": [ + "boolean", + "null" + ] +} - added
Input schema / properties / MEDIA_LINK_RETENTION_DAYSAdded value: +{ + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Delete revoked and expired share links this many days after they stopped working. 0 = keep forever." +} - added
Input schema / properties / MEDIA_LINK_TTL_DAYSAdded value: +{ + "anyOf": [ + { + "maximum": 3650, + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Share links last this many days unless the owner picks less." +} - added
Input schema / properties / WEBHOOK_DELIVERY_RETENTION_DAYSAdded value: +{ + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Delete webhook delivery log rows older than this. 0 = keep forever." +}
- Added
test_webhook - Changed
update_project1 field changed- added
Input schema / properties / metadataAdded value: +{ + "additionalProperties": { + "maxLength": 500, + "type": "string" + }, + "description": "Replace the project's metadata (the whole map; {} clears it)", + "propertyNames": { + "pattern": "^[A-Za-z0-9_.-]{1,40}$", + "type": "string" + }, + "type": "object" +}
- Added
update_webhook
14 tool updates
v0.28.1- Changed
create_project1 field changed- added
Input schema / properties / settings / properties / captionSeamAdded value: +{ + "description": "In split and stack sections, put captions on the line between the two panes instead of at captionY (default true)", + "type": "boolean" +}
- Changed
delete_project1 field changed- added
Input schema / properties / forgetDecisionsAdded value: +{ + "default": false, + "description": "Forget what Reelsaw learned from it (its decision log entries) when it is deleted for good, by purge_project or the retention sweep; restoring it cancels that. Default false keeps them", + "type": "boolean" +}
- Added
export_decisions - Added
forget_decisions - Added
list_decisions - Changed
purge_project1 field changed- added
Input schema / properties / forgetDecisionsAdded value: +{ + "default": false, + "description": "Also forget what Reelsaw learned from this project (its entries in the decision log); default false keeps them", + "type": "boolean" +}
- Changed
reanalyze_project1 field changed- added
Input schema / properties / settings / properties / captionSeamAdded value: +{ + "description": "In split and stack sections, put captions on the line between the two panes instead of at captionY (default true)", + "type": "boolean" +}
- Changed
save_layer_template1 field changed- added
Input schema / properties / bumpersAdded value: +{ + "description": "With layers: the intro / outro the template puts on clips ({ intro, introSec, outro, outroSec }; a slot left out = clips keep their own, null = none, an id = that video or image). With clipId the clip's intro and outro are saved too", + "properties": { + "intro": { + "anyOf": [ + { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Library video or image id (list_bumpers) for the intro; null = no intro; left out = clips keep their own" + }, + "introSec": { + "description": "Seconds an image intro/outro shows (1-10); videos keep their own length", + "maximum": 10, + "minimum": 1, + "type": "number" + }, + "outro": { + "anyOf": [ + { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Library video or image id (list_bumpers) for the outro; null = no outro; left out = clips keep their own" + }, + "outroSec": { + "description": "Seconds an image intro/outro shows (1-10); videos keep their own length", + "maximum": 10, + "minimum": 1, + "type": "number" + } + }, + "type": "object" +}
- Changed
set_instance_settings2 fields changed- added
Input schema / properties / DECISION_RETENTION_DAYSAdded value: +{ + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Prune users' recorded decisions (accepts, rejects, edits Reelsaw learns from) older than this. They outlive deleted projects until then. 0 = keep forever." +} - changed
Input schema / properties / LLM_CALL_TIMEOUT_SECONDS / descriptionPrevious value: -"Longest one model call may take (all its HTTP attempts together) before its step is stopped and retried. 0 = auto: 120 s for a hosted model, 600 s for a self-hosted one. A slow CPU-only model may need more."New value: +"Longest one model call may take (all its HTTP attempts together) before its step is stopped and retried. 0 = auto: 120 s for a hosted model, 600 s for a self-hosted one, and for a self-hosted transcription at least twice the chunk's audio length. Time spent waiting for a provider slot does not count. A slow CPU-only model may need more."
- Added
set_learning - Changed
update_clip1 field changed- changed
Input schema / properties / style / anyOfPrevious 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" - } -]New value: +[ + { + "properties": { + "captionSeam": { + "description": "In split and stack sections, put captions on the line between the two panes instead of at captionY (default true)", + "type": "boolean" + }, + "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" + } +]
- Changed
update_layer_template1 field changed- added
Input schema / properties / bumpersAdded value: +{ + "anyOf": [ + { + "description": "Intro / outro the template puts on clips, as each clip's own choice", + "properties": { + "intro": { + "anyOf": [ + { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Library video or image id (list_bumpers) for the intro; null = no intro; left out = clips keep their own" + }, + "introSec": { + "description": "Seconds an image intro/outro shows (1-10); videos keep their own length", + "maximum": 10, + "minimum": 1, + "type": "number" + }, + "outro": { + "anyOf": [ + { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Library video or image id (list_bumpers) for the outro; null = no outro; left out = clips keep their own" + }, + "outroSec": { + "description": "Seconds an image intro/outro shows (1-10); videos keep their own length", + "maximum": 10, + "minimum": 1, + "type": "number" + } + }, + "type": "object" + }, + { + "type": "null" + } + ] +}
- Changed
update_project1 field changed- added
Input schema / properties / settings / properties / captionSeamAdded value: +{ + "description": "In split and stack sections, put captions on the line between the two panes instead of at captionY (default true)", + "type": "boolean" +}
- Changed
update_project_style1 field changed- added
Input schema / properties / style / properties / captionSeamAdded value: +{ + "description": "In split and stack sections, put captions on the line between the two panes instead of at captionY (default true)", + "type": "boolean" +}
27 tool updates
v0.26.3- Added
add_transcript_correction - Added
add_transcript_cut - Added
billing_portal_url - Changed
create_project3 fields changed- changed
Input schema / properties / sourceUrl / descriptionPrevious value: -"http(s) URL of the video"New value: +"http(s) URL of the video; give this or uploadId" - added
Input schema / properties / uploadIdAdded value: +{ + "description": "Id returned by POST /api/upload (the file body, x-filename header, API key as Bearer); give this or sourceUrl", + "maxLength": 100, + "minLength": 1, + "type": "string" +} - removed
Input schema / requiredRemoved value: -[ - "sourceUrl" -]
- Added
delete_asset - Added
delete_clips - Added
delete_layer_template - Added
get_project_defaults - Added
list_deleted - Changed
list_layer_templates2 fields changed- added
Input schema / properties / cursorAdded value: +{ + "description": "nextCursor from the previous page; omit for the first page", + "maxLength": 300, + "type": "string" +} - added
Input schema / properties / limitAdded value: +{ + "default": 100, + "description": "Templates per page (1-500, default 100)", + "maximum": 500, + "minimum": 1, + "type": "integer" +}
- Added
list_transcript_flags - Added
purge_asset - Added
purge_clip - Added
purge_layer_template - Added
purge_project - Added
refine_project - Removed
remove_asset - Removed
remove_layer_template - Changed
restore_asset1 field changed- changed
Input schema / properties / assetId / descriptionPrevious value: -"Library asset id (from remove_asset)"New value: +"Library asset id (from delete_asset)"
- Changed
restore_clip1 field changed- changed
Input schema / properties / id / descriptionPrevious value: -"Clip id (from get_project → replacedClips)"New value: +"Clip id (from list_deleted or get_project → replacedClips)"
- Added
review_transcript_flags - Changed
search_assets2 fields changed- added
Input schema / properties / deletedAdded value: +{ + "description": "library only: list your deleted items instead (their ids go to restore_asset)", + "type": "boolean" +} - removed
Input schema / properties / removedRemoved value: -{ - "description": "library only: list the items removed in the last 30 days instead (their ids go to restore_asset)", - "type": "boolean" -}
- Changed
set_instance_settings6 fields changed- added
Input schema / properties / LLM_CALL_TIMEOUT_SECONDSAdded value: +{ + "anyOf": [ + { + "maximum": 86400, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Longest one model call may take (all its HTTP attempts together) before its step is stopped and retried. 0 = auto: 120 s for a hosted model, 600 s for a self-hosted one. A slow CPU-only model may need more." +} - changed
Input schema / properties / MAX_RERENDERS_PER_HOUR / descriptionPrevious value: -"Re-renders and hand-made clips an account may ask for per hour. 0 = unlimited."New value: +"Re-renders, hand-made clips and re-runs (re-analyze, refine) an account may ask for per hour. 0 = unlimited." - changed
Input schema / properties / MAX_STORAGE_MB / descriptionPrevious value: -"MB of sources, uploads, renders and intros/outros an account may keep. 0 = unlimited."New value: +"MB of sources, uploads, renders and intros/outros an account may keep (deleted items count until they are deleted forever). 0 = unlimited." - added
Input schema / properties / SCRATCH_CACHE_HOURSAdded value: +{ + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "With an S3 store, drop a worker's local copies of the sources and rendered clips of finished projects after this many idle hours; a job pulls them back from the bucket when it needs them, and a worker short of disk drops the least recently used ones first. 0 = keep them on the worker. The local store needs nothing: scratch and store are the same file." +} - added
Input schema / properties / STAGE_IDLE_TIMEOUT_MINUTESAdded value: +{ + "anyOf": [ + { + "maximum": 1440, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "A stage made of checkpointed steps (finding moments) is stopped when no step has finished for this long; Retry continues where it stopped. 0 = auto: 1.5 times the model call timeout." +} - added
Input schema / properties / STEP_RETENTION_DAYSAdded value: +{ + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Drop the saved checkpoints (finding-moments windows) of a finished project this many days after it last changed; a Retry sooner than that reuses them. 0 = keep forever." +}
- Added
set_project_defaults - Added
set_project_source_text - Changed
update_clip1 field changed- changed
Input schema / properties / rerender / descriptionPrevious value: -"Re-render when a burned-in field changed (default true); false = keep the old video until rerender_clip"New value: +"Re-render when a burned-in field changed (default true, same as the app); false = keep the old video until rerender_clip"
- Added
update_project_style
13 tool updates
v0.23.0- Added
apply_framing - Added
apply_layer_template - Changed
create_project5 fields changed- changed
Input schema / properties / settings / descriptionPrevious value: -"Project settings; omit for the defaults (automatic clip count, 20–60 s clips, natural pauses, refine steps off). Set refineEntities / refineDisfluency / disfluencyLlm / refineScenes true to opt into polish (instance Pipeline gates must be on)."New value: +"Project settings; omit for the defaults (automatic clip count, 20–60 s clips, natural pauses, name fixes and the on-screen text scan on, filler removal off). Set refineDisfluency / disfluencyLlm true to opt into filler removal, refineEntities / refineScenes false to skip those steps (instance Pipeline gates must be on)." - added
Input schema / properties / settings / properties / layerTemplateIdAdded value: +{ + "anyOf": [ + { + "maxLength": 100, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Layer template id (list_layer_templates) applied to each new clip of this project; null = none. Existing clips: apply_layer_template" +} - changed
Input schema / properties / settings / properties / refineEntities / descriptionPrevious value: -"Fix misheard names after transcription (LLM). Off by default; on runs that refine step."New value: +"Fix misheard names after transcription (LLM). On by default; off skips that refine step." - changed
Input schema / properties / settings / properties / refineScenes / descriptionPrevious value: -"Detect scene cuts and on-screen text. Off by default; on runs that refine step."New value: +"Scan the video for on-screen text (burned-in captions, watermarks, slides). On by default; off skips that refine step. Shot cuts are always detected." - added
Input schema / properties / settings / properties / reframeAdjustAdded value: +{ + "anyOf": [ + { + "properties": { + "contentCrop": { + "description": "Stack only: the part of the frame shown on top instead of the whole frame or the detected content region", + "properties": { + "x1": { + "description": "Left edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "x2": { + "description": "Right edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y1": { + "description": "Top edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y2": { + "description": "Bottom edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "x1", + "y1", + "x2", + "y2" + ], + "type": "object" + }, + "crop": { + "description": "Show exactly this part of the source in the (top / only) pane, as fractions of the source size; replaces the automatic crop, the offset and the subject. A shape unlike the pane's is fitted over a blurred copy", + "properties": { + "x1": { + "description": "Left edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "x2": { + "description": "Right edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y1": { + "description": "Top edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y2": { + "description": "Bottom edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "x1", + "y1", + "x2", + "y2" + ], + "type": "object" + }, + "crop2": { + "description": "Split only: a fixed crop for the bottom pane", + "properties": { + "x1": { + "description": "Left edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "x2": { + "description": "Right edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y1": { + "description": "Top edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y2": { + "description": "Bottom edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "x1", + "y1", + "x2", + "y2" + ], + "type": "object" + }, + "offsetX": { + "description": "Shift the (top) crop sideways by this fraction of the source width (-0.5 to 0.5), relative to the face it follows", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetX2": { + "description": "Split only: shift the bottom crop sideways (-0.5 to 0.5)", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetY": { + "description": "Shift the (top) crop up or down by this fraction of the source height; only matters where the crop is shorter than the frame (split, stack)", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetY2": { + "description": "Split only: shift the bottom crop up or down (-0.5 to 0.5)", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "subjectX": { + "description": "Follow the person at this x (0-1 of the source width) in the top/only pane; the offset still applies on top", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "subjectX2": { + "description": "Split only: follow the person at this x in the bottom pane", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Applied with reframe to clips without their own sections: offsetX/Y, offsetX2/Y2, subjectX/X2, crop, crop2, contentCrop as on a clip's section; null = none. apply_framing sets it from one clip" +}
- Added
list_layer_templates - Added
list_releases - Changed
reanalyze_project5 fields changed- changed
Input schema / properties / settings / descriptionPrevious value: -"Project settings; omit for the defaults (automatic clip count, 20–60 s clips, natural pauses, refine steps off). Set refineEntities / refineDisfluency / disfluencyLlm / refineScenes true to opt into polish (instance Pipeline gates must be on)."New value: +"Project settings; omit for the defaults (automatic clip count, 20–60 s clips, natural pauses, name fixes and the on-screen text scan on, filler removal off). Set refineDisfluency / disfluencyLlm true to opt into filler removal, refineEntities / refineScenes false to skip those steps (instance Pipeline gates must be on)." - added
Input schema / properties / settings / properties / layerTemplateIdAdded value: +{ + "anyOf": [ + { + "maxLength": 100, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Layer template id (list_layer_templates) applied to each new clip of this project; null = none. Existing clips: apply_layer_template" +} - changed
Input schema / properties / settings / properties / refineEntities / descriptionPrevious value: -"Fix misheard names after transcription (LLM). Off by default; on runs that refine step."New value: +"Fix misheard names after transcription (LLM). On by default; off skips that refine step." - changed
Input schema / properties / settings / properties / refineScenes / descriptionPrevious value: -"Detect scene cuts and on-screen text. Off by default; on runs that refine step."New value: +"Scan the video for on-screen text (burned-in captions, watermarks, slides). On by default; off skips that refine step. Shot cuts are always detected." - added
Input schema / properties / settings / properties / reframeAdjustAdded value: +{ + "anyOf": [ + { + "properties": { + "contentCrop": { + "description": "Stack only: the part of the frame shown on top instead of the whole frame or the detected content region", + "properties": { + "x1": { + "description": "Left edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "x2": { + "description": "Right edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y1": { + "description": "Top edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y2": { + "description": "Bottom edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "x1", + "y1", + "x2", + "y2" + ], + "type": "object" + }, + "crop": { + "description": "Show exactly this part of the source in the (top / only) pane, as fractions of the source size; replaces the automatic crop, the offset and the subject. A shape unlike the pane's is fitted over a blurred copy", + "properties": { + "x1": { + "description": "Left edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "x2": { + "description": "Right edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y1": { + "description": "Top edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y2": { + "description": "Bottom edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "x1", + "y1", + "x2", + "y2" + ], + "type": "object" + }, + "crop2": { + "description": "Split only: a fixed crop for the bottom pane", + "properties": { + "x1": { + "description": "Left edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "x2": { + "description": "Right edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y1": { + "description": "Top edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y2": { + "description": "Bottom edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "x1", + "y1", + "x2", + "y2" + ], + "type": "object" + }, + "offsetX": { + "description": "Shift the (top) crop sideways by this fraction of the source width (-0.5 to 0.5), relative to the face it follows", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetX2": { + "description": "Split only: shift the bottom crop sideways (-0.5 to 0.5)", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetY": { + "description": "Shift the (top) crop up or down by this fraction of the source height; only matters where the crop is shorter than the frame (split, stack)", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetY2": { + "description": "Split only: shift the bottom crop up or down (-0.5 to 0.5)", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "subjectX": { + "description": "Follow the person at this x (0-1 of the source width) in the top/only pane; the offset still applies on top", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "subjectX2": { + "description": "Split only: follow the person at this x in the bottom pane", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Applied with reframe to clips without their own sections: offsetX/Y, offsetX2/Y2, subjectX/X2, crop, crop2, contentCrop as on a clip's section; null = none. apply_framing sets it from one clip" +}
- Added
remove_layer_template - Added
restore_layer_template - Added
save_layer_template - Changed
set_instance_settings2 fields changed- changed
Input schema / properties / REFINE_SCENES / descriptionPrevious value: -"Detect scene cuts and on-screen text during refine. Off by default; turn on so projects may opt in via refineScenes."New value: +"Scan the video for on-screen text (burned-in captions, watermarks, slides) during refine. On by default; off closes the ceiling (projects opt out via refineScenes). Shot cuts are always detected." - changed
Input schema / properties / TRANSCRIPT_CORRECTION / descriptionPrevious value: -"After transcription, fix misheard names with the language model. Off by default (ceiling closed); turn on so projects may opt in via refineEntities."New value: +"After transcription, fix misheard names with the language model. On by default; off closes the ceiling so no project runs it (projects opt out via refineEntities)."
- Changed
update_clip1 field changed- changed
Input schema / properties / layoutSections / anyOfPrevious 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 (top) crop sideways by this fraction of the source width (-0.5 to 0.5), relative to the face it follows", - "maximum": 0.5, - "minimum": -0.5, - "type": "number" - }, - "offsetX2": { - "description": "Split only: shift the bottom crop sideways (-0.5 to 0.5)", - "maximum": 0.5, - "minimum": -0.5, - "type": "number" - }, - "offsetY": { - "description": "Shift the (top) crop up or down by this fraction of the source height; only matters where the crop is shorter than the frame (split, stack)", - "maximum": 0.5, - "minimum": -0.5, - "type": "number" - }, - "offsetY2": { - "description": "Split only: shift the bottom crop up or down (-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" - }, - "subjectX": { - "description": "Follow the person at this x (0-1 of the source width) in the top/only pane; the offset still applies on top", - "maximum": 1, - "minimum": 0, - "type": "number" - }, - "subjectX2": { - "description": "Split only: follow the person at this x in the bottom pane", - "maximum": 1, - "minimum": 0, - "type": "number" - } - }, - "required": [ - "start", - "end", - "mode" - ], - "type": "object" - }, - "maxItems": 50, - "type": "array" - }, - { - "type": "null" - } -]New value: +[ + { + "items": { + "properties": { + "contentCrop": { + "description": "Stack only: the part of the frame shown on top instead of the whole frame or the detected content region", + "properties": { + "x1": { + "description": "Left edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "x2": { + "description": "Right edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y1": { + "description": "Top edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y2": { + "description": "Bottom edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "x1", + "y1", + "x2", + "y2" + ], + "type": "object" + }, + "crop": { + "description": "Show exactly this part of the source in the (top / only) pane, as fractions of the source size; replaces the automatic crop, the offset and the subject. A shape unlike the pane's is fitted over a blurred copy", + "properties": { + "x1": { + "description": "Left edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "x2": { + "description": "Right edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y1": { + "description": "Top edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y2": { + "description": "Bottom edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "x1", + "y1", + "x2", + "y2" + ], + "type": "object" + }, + "crop2": { + "description": "Split only: a fixed crop for the bottom pane", + "properties": { + "x1": { + "description": "Left edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "x2": { + "description": "Right edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y1": { + "description": "Top edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y2": { + "description": "Bottom edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "x1", + "y1", + "x2", + "y2" + ], + "type": "object" + }, + "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 (top) crop sideways by this fraction of the source width (-0.5 to 0.5), relative to the face it follows", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetX2": { + "description": "Split only: shift the bottom crop sideways (-0.5 to 0.5)", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetY": { + "description": "Shift the (top) crop up or down by this fraction of the source height; only matters where the crop is shorter than the frame (split, stack)", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetY2": { + "description": "Split only: shift the bottom crop up or down (-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" + }, + "subjectX": { + "description": "Follow the person at this x (0-1 of the source width) in the top/only pane; the offset still applies on top", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "subjectX2": { + "description": "Split only: follow the person at this x in the bottom pane", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "start", + "end", + "mode" + ], + "type": "object" + }, + "maxItems": 50, + "type": "array" + }, + { + "type": "null" + } +]
- Added
update_layer_template - Changed
update_project6 fields changed- changed
Input schema / properties / clear / items / enumPrevious value: -[ - "maxClips", - "focus", - "instructions", - "language", - "vocabulary" -]New value: +[ + "maxClips", + "focus", + "instructions", + "language", + "vocabulary", + "reframeAdjust" +] - changed
Input schema / properties / clear / maxItemsPrevious value: -5New value: +6 - added
Input schema / properties / settings / properties / layerTemplateIdAdded value: +{ + "anyOf": [ + { + "maxLength": 100, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Layer template id (list_layer_templates) applied to each new clip of this project; null = none. Existing clips: apply_layer_template" +} - changed
Input schema / properties / settings / properties / refineEntities / descriptionPrevious value: -"Fix misheard names after transcription (LLM). Off by default; on runs that refine step."New value: +"Fix misheard names after transcription (LLM). On by default; off skips that refine step." - changed
Input schema / properties / settings / properties / refineScenes / descriptionPrevious value: -"Detect scene cuts and on-screen text. Off by default; on runs that refine step."New value: +"Scan the video for on-screen text (burned-in captions, watermarks, slides). On by default; off skips that refine step. Shot cuts are always detected." - added
Input schema / properties / settings / properties / reframeAdjustAdded value: +{ + "anyOf": [ + { + "properties": { + "contentCrop": { + "description": "Stack only: the part of the frame shown on top instead of the whole frame or the detected content region", + "properties": { + "x1": { + "description": "Left edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "x2": { + "description": "Right edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y1": { + "description": "Top edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y2": { + "description": "Bottom edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "x1", + "y1", + "x2", + "y2" + ], + "type": "object" + }, + "crop": { + "description": "Show exactly this part of the source in the (top / only) pane, as fractions of the source size; replaces the automatic crop, the offset and the subject. A shape unlike the pane's is fitted over a blurred copy", + "properties": { + "x1": { + "description": "Left edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "x2": { + "description": "Right edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y1": { + "description": "Top edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y2": { + "description": "Bottom edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "x1", + "y1", + "x2", + "y2" + ], + "type": "object" + }, + "crop2": { + "description": "Split only: a fixed crop for the bottom pane", + "properties": { + "x1": { + "description": "Left edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "x2": { + "description": "Right edge, fraction of the source width", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y1": { + "description": "Top edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y2": { + "description": "Bottom edge, fraction of the source height", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "x1", + "y1", + "x2", + "y2" + ], + "type": "object" + }, + "offsetX": { + "description": "Shift the (top) crop sideways by this fraction of the source width (-0.5 to 0.5), relative to the face it follows", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetX2": { + "description": "Split only: shift the bottom crop sideways (-0.5 to 0.5)", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetY": { + "description": "Shift the (top) crop up or down by this fraction of the source height; only matters where the crop is shorter than the frame (split, stack)", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetY2": { + "description": "Split only: shift the bottom crop up or down (-0.5 to 0.5)", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "subjectX": { + "description": "Follow the person at this x (0-1 of the source width) in the top/only pane; the offset still applies on top", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "subjectX2": { + "description": "Split only: follow the person at this x in the bottom pane", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Applied with reframe to clips without their own sections: offsetX/Y, offsetX2/Y2, subjectX/X2, crop, crop2, contentCrop as on a clip's section; null = none. apply_framing sets it from one clip" +}
18 tool updates
v0.19.1- Added
add_asset - Removed
add_bumper - Added
asset_usage - Removed
bumper_usage - Changed
create_project3 fields changed- changed
Input schema / properties / introAssetId / descriptionPrevious value: -"Library asset id (list_bumpers) for the intro of every clip; null = no intro; omitted = your default intro"New value: +"Library asset id (search_assets with source library) for the intro of every clip; null = no intro; omitted = your default intro" - changed
Input schema / properties / settings / properties / introAssetId / descriptionPrevious value: -"Library asset id of the intro (list_bumpers); null = none"New value: +"Library asset id of the intro (search_assets with source library); null = none" - changed
Input schema / properties / settings / properties / outroAssetId / descriptionPrevious value: -"Library asset id of the outro (list_bumpers); null = none"New value: +"Library asset id of the outro (search_assets with source library); null = none"
- Removed
list_bumpers - Changed
reanalyze_project2 fields changed- changed
Input schema / properties / settings / properties / introAssetId / descriptionPrevious value: -"Library asset id of the intro (list_bumpers); null = none"New value: +"Library asset id of the intro (search_assets with source library); null = none" - changed
Input schema / properties / settings / properties / outroAssetId / descriptionPrevious value: -"Library asset id of the outro (list_bumpers); null = none"New value: +"Library asset id of the outro (search_assets with source library); null = none"
- Added
remove_asset - Removed
remove_bumper - Removed
rename_bumper - Added
restore_asset - Removed
restore_bumper - Added
search_assets - Changed
set_default_bumper1 field changed- changed
Input schema / properties / assetId / descriptionPrevious value: -"Library asset id (list_bumpers), or null for no default"New value: +"Library asset id (search_assets with source library), or null for no default"
- Changed
set_instance_settings10 fields changed- added
Input schema / properties / CATALOG_URLAdded value: +{ + "anyOf": [ + { + "format": "uri", + "maxLength": 500, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Where the Reelsaw catalog manifest (sounds, icons, stickers) is fetched from, hourly; the starter pack bundled with Reelsaw is used until a newer one arrives." +} - added
Input schema / properties / FREESOUND_API_KEYAdded value: +{ + "anyOf": [ + { + "maxLength": 200, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Freesound API key (free): enables sound effects in Browse. Stored encrypted; empty = provider hidden." +} - added
Input schema / properties / GIPHY_API_KEYAdded value: +{ + "anyOf": [ + { + "maxLength": 200, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Giphy API key: enables GIFs and stickers in Browse. Stored encrypted; empty = provider hidden." +} - added
Input schema / properties / ICONIFY_API_URLAdded value: +{ + "anyOf": [ + { + "format": "uri", + "maxLength": 500, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Iconify API used for icon search; the public one by default, or your own self-hosted instance (https)." +} - added
Input schema / properties / KLIPY_API_KEYAdded value: +{ + "anyOf": [ + { + "maxLength": 200, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Klipy API key: enables GIF search in Browse (experimental). Stored encrypted; empty = provider hidden." +} - added
Input schema / properties / OPENVERSE_ENABLEDAdded value: +{ + "description": "Show Openverse (Creative Commons images and audio, no key) in Browse. Off by default until you have checked its limits for your use.", + "type": [ + "boolean", + "null" + ] +} - added
Input schema / properties / PEXELS_API_KEYAdded value: +{ + "anyOf": [ + { + "maxLength": 200, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Pexels API key (free): enables stock photos and portrait videos in Browse. Stored encrypted; empty = provider hidden." +} - added
Input schema / properties / PIXABAY_API_KEYAdded value: +{ + "anyOf": [ + { + "maxLength": 200, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Pixabay API key (free): enables photos, illustrations, vectors and videos in Browse. Stored encrypted; empty = provider hidden." +} - changed
Input schema / properties / REQUIRE_EMAIL_VERIFICATION / descriptionPrevious value: -"New users must click the verification link before they can sign in. Needs an email driver in .env."New value: +"New users must click the verification link before they can sign in. The link works for 24 hours and is single-use; an expired one offers a new send. Needs an email driver in .env." - changed
Input schema / properties / SIGNUP_MODE / descriptionPrevious value: -"Who may sign up: open (anyone), approval (new accounts wait for an admin) or closed (nobody). The first account is always the admin."New value: +"Who may sign up: open (anyone, right for a public instance with email confirmation), approval (new accounts wait for an admin; a private box) or closed (nobody). The first account is always the admin."
- Added
update_asset - Changed
update_clip3 fields changed- removed
Input schema / properties / audioRemoved value: -{ - "anyOf": [ - { - "items": { - "properties": { - "assetId": { - "description": "Library audio asset id (list_bumpers, kind audio); the same asset can be used more than once", - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "duck": { - "description": "Lower the music while someone speaks (default true)", - "type": "boolean" - }, - "end": { - "description": "Music stops after this second of the source video", - "minimum": 0, - "type": "number" - }, - "fade": { - "description": "Fade in and out, seconds (default 0.5)", - "maximum": 5, - "minimum": 0, - "type": "number" - }, - "id": { - "description": "Stable id for this track (any short string; keep it when editing)", - "maxLength": 40, - "minLength": 1, - "type": "string" - }, - "loop": { - "description": "Repeat the track when it is shorter than the window (default true)", - "type": "boolean" - }, - "offset": { - "description": "Seconds into the track to start from (default 0)", - "minimum": 0, - "type": "number" - }, - "start": { - "description": "Music starts at this second of the source video", - "minimum": 0, - "type": "number" - }, - "volume": { - "description": "Music level 0-1 (default 0.6) on a track normalised to -20 LUFS, before ducking", - "maximum": 1, - "minimum": 0, - "type": "number" - } - }, - "required": [ - "id", - "assetId", - "start", - "end" - ], - "type": "object" - }, - "maxItems": 10, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Background music tracks under parts of the clip (max 10; the same asset may repeat): library audio assets (list_bumpers, kind audio), each with a window in source seconds, volume, ducking under speech, fades. Replaces the list; null or [] = none" -} - added
Input schema / properties / layersAdded value: +{ + "anyOf": [ + { + "items": { + "oneOf": [ + { + "properties": { + "assetId": { + "description": "Library asset id (search_assets with source library): an image, an animation or a video", + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "end": { + "description": "Hidden after this second of the source video", + "minimum": 0, + "type": "number" + }, + "id": { + "description": "Stable id for this overlay (any short string; keep it when editing)", + "maxLength": 40, + "minLength": 1, + "type": "string" + }, + "kind": { + "const": "asset", + "type": "string" + }, + "loop": { + "description": "Repeat a video / animation while its window is open (default: on for GIF and animated WebP, off for videos)", + "type": "boolean" + }, + "opacity": { + "description": "0.1-1, default 1", + "maximum": 1, + "minimum": 0.1, + "type": "number" + }, + "start": { + "description": "Shown from this second of the source video", + "minimum": 0, + "type": "number" + }, + "w": { + "description": "asset: width, fraction of the output width (0.05-1); the height follows the file. Default 0.3", + "maximum": 1, + "minimum": 0.05, + "type": "number" + }, + "x": { + "description": "Centre, fraction of the output width (0-1)", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y": { + "description": "Centre, fraction of the output height (0-1)", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "id", + "assetId", + "start", + "end", + "x", + "y", + "kind" + ], + "type": "object" + }, + { + "properties": { + "box": { + "description": "text: dark plate behind the text (default: outlined text, no plate)", + "type": "boolean" + }, + "color": { + "description": "text: colour as #RRGGBB, default white", + "pattern": "^#[0-9a-fA-F]{6}$", + "type": "string" + }, + "end": { + "description": "Hidden after this second of the source video", + "minimum": 0, + "type": "number" + }, + "font": { + "description": "text: font family from TEXT_FONTS (default DejaVu Sans, the caption font)", + "maxLength": 60, + "minLength": 1, + "type": "string" + }, + "id": { + "description": "Stable id for this overlay (any short string; keep it when editing)", + "maxLength": 40, + "minLength": 1, + "type": "string" + }, + "kind": { + "const": "text", + "type": "string" + }, + "opacity": { + "description": "0.1-1, default 1", + "maximum": 1, + "minimum": 0.1, + "type": "number" + }, + "size": { + "description": "text: font size as a fraction of the output height (0.02-0.12), default 0.045", + "maximum": 0.12, + "minimum": 0.02, + "type": "number" + }, + "start": { + "description": "Shown from this second of the source video", + "minimum": 0, + "type": "number" + }, + "text": { + "description": "The line to show (1-120 chars)", + "maxLength": 120, + "minLength": 1, + "type": "string" + }, + "x": { + "description": "Centre, fraction of the output width (0-1)", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y": { + "description": "Centre, fraction of the output height (0-1)", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "id", + "text", + "start", + "end", + "x", + "y", + "kind" + ], + "type": "object" + }, + { + "properties": { + "assetId": { + "description": "Library audio asset id (search_assets with source library, kind audio); the same asset can be used more than once", + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "duck": { + "description": "Lower the music while someone speaks (default true)", + "type": "boolean" + }, + "end": { + "description": "Music stops after this second of the source video", + "minimum": 0, + "type": "number" + }, + "fade": { + "description": "Fade in and out, seconds (default 0.5)", + "maximum": 5, + "minimum": 0, + "type": "number" + }, + "id": { + "description": "Stable id for this track (any short string; keep it when editing)", + "maxLength": 40, + "minLength": 1, + "type": "string" + }, + "kind": { + "const": "audio", + "type": "string" + }, + "loop": { + "description": "Repeat the track when it is shorter than the window (default true)", + "type": "boolean" + }, + "offset": { + "description": "Seconds into the track to start from (default 0)", + "minimum": 0, + "type": "number" + }, + "start": { + "description": "Music starts at this second of the source video", + "minimum": 0, + "type": "number" + }, + "volume": { + "description": "Music level 0-1 (default 0.6) on a track normalised to -20 LUFS, before ducking", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "id", + "assetId", + "start", + "end", + "kind" + ], + "type": "object" + } + ] + }, + "maxItems": 30, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Everything laid over or played under the clip, one list (max 30): kind asset = a library image/GIF/video (search_assets with source library; logos, stickers, b-roll), kind text = a line of text, kind audio = music or a sound effect (a library audio asset with a window in source seconds, volume, ducking, fade, loop). Replaces the whole list; null or [] = none. get_clip returns it" +} - removed
Input schema / properties / overlaysRemoved value: -{ - "anyOf": [ - { - "items": { - "properties": { - "assetId": { - "description": "asset: library asset id (list_bumpers), an image or a video", - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "box": { - "description": "text: dark plate behind the text (default: outlined text, no plate)", - "type": "boolean" - }, - "color": { - "description": "text: colour as #RRGGBB, default white", - "pattern": "^#[0-9a-fA-F]{6}$", - "type": "string" - }, - "end": { - "description": "Hidden after this second of the source video", - "minimum": 0, - "type": "number" - }, - "font": { - "description": "text: font family from TEXT_FONTS (default DejaVu Sans, the caption font)", - "maxLength": 60, - "minLength": 1, - "type": "string" - }, - "id": { - "description": "Stable id for this overlay (any short string; keep it when editing)", - "maxLength": 40, - "minLength": 1, - "type": "string" - }, - "kind": { - "description": "asset (default): a library image or video; text: a line of text", - "enum": [ - "asset", - "text" - ], - "type": "string" - }, - "opacity": { - "description": "0.1-1, default 1", - "maximum": 1, - "minimum": 0.1, - "type": "number" - }, - "size": { - "description": "text: font size as a fraction of the output height (0.02-0.12), default 0.045", - "maximum": 0.12, - "minimum": 0.02, - "type": "number" - }, - "start": { - "description": "Shown from this second of the source video", - "minimum": 0, - "type": "number" - }, - "text": { - "description": "text: the line to show (1-120 chars)", - "maxLength": 120, - "minLength": 1, - "type": "string" - }, - "w": { - "description": "asset: width, fraction of the output width (0.05-1); the height follows the file. Default 0.3", - "maximum": 1, - "minimum": 0.05, - "type": "number" - }, - "x": { - "description": "Centre, fraction of the output width (0-1)", - "maximum": 1, - "minimum": 0, - "type": "number" - }, - "y": { - "description": "Centre, fraction of the output height (0-1)", - "maximum": 1, - "minimum": 0, - "type": "number" - } - }, - "required": [ - "id", - "start", - "end", - "x", - "y" - ], - "type": "object" - }, - "maxItems": 20, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Things laid over the clip for a time range (max 20): kind asset = a library image/video (list_bumpers; logos, stickers, b-roll), kind text = a line of text (size, color, box). Replaces the list; null or [] = none" -}
- Changed
update_project2 fields changed- changed
Input schema / properties / settings / properties / introAssetId / descriptionPrevious value: -"Library asset id of the intro (list_bumpers); null = none"New value: +"Library asset id of the intro (search_assets with source library); null = none" - changed
Input schema / properties / settings / properties / outroAssetId / descriptionPrevious value: -"Library asset id of the outro (list_bumpers); null = none"New value: +"Library asset id of the outro (search_assets with source library); null = none"
18 tool updates
v0.17.0- Added
billing_checkout_url - Added
check_for_update - Changed
create_project5 fields changed- changed
Input schema / properties / settings / descriptionPrevious value: -"Project settings; omit for the defaults (automatic clip count, 20–60 s clips, natural pauses)."New value: +"Project settings; omit for the defaults (automatic clip count, 20–60 s clips, natural pauses, refine steps off). Set refineEntities / refineDisfluency / disfluencyLlm / refineScenes true to opt into polish (instance Pipeline gates must be on)." - added
Input schema / properties / settings / properties / disfluencyLlmAdded value: +{ + "description": "Model pass on top of rule-based disfluency detection. Off by default (rules only when disfluency is on).", + "type": "boolean" +} - added
Input schema / properties / settings / properties / refineDisfluencyAdded value: +{ + "description": "Find fillers, repetitions and false starts. Off by default; on runs that refine step.", + "type": "boolean" +} - added
Input schema / properties / settings / properties / refineEntitiesAdded value: +{ + "description": "Fix misheard names after transcription (LLM). Off by default; on runs that refine step.", + "type": "boolean" +} - added
Input schema / properties / settings / properties / refineScenesAdded value: +{ + "description": "Detect scene cuts and on-screen text. Off by default; on runs that refine step.", + "type": "boolean" +}
- Added
get_billing - Added
get_clip_captions - Added
get_failure - Added
get_instance_settings - Added
get_project_transcript_file - Added
get_queue - Added
import_transcript - Added
list_failures - Added
list_workers - Changed
reanalyze_project5 fields changed- changed
Input schema / properties / settings / descriptionPrevious value: -"Project settings; omit for the defaults (automatic clip count, 20–60 s clips, natural pauses)."New value: +"Project settings; omit for the defaults (automatic clip count, 20–60 s clips, natural pauses, refine steps off). Set refineEntities / refineDisfluency / disfluencyLlm / refineScenes true to opt into polish (instance Pipeline gates must be on)." - added
Input schema / properties / settings / properties / disfluencyLlmAdded value: +{ + "description": "Model pass on top of rule-based disfluency detection. Off by default (rules only when disfluency is on).", + "type": "boolean" +} - added
Input schema / properties / settings / properties / refineDisfluencyAdded value: +{ + "description": "Find fillers, repetitions and false starts. Off by default; on runs that refine step.", + "type": "boolean" +} - added
Input schema / properties / settings / properties / refineEntitiesAdded value: +{ + "description": "Fix misheard names after transcription (LLM). Off by default; on runs that refine step.", + "type": "boolean" +} - added
Input schema / properties / settings / properties / refineScenesAdded value: +{ + "description": "Detect scene cuts and on-screen text. Off by default; on runs that refine step.", + "type": "boolean" +}
- Added
report_issue - Added
retry_failures - Added
set_instance_settings - Changed
update_clip3 fields changed- added
Input schema / properties / audioAdded value: +{ + "anyOf": [ + { + "items": { + "properties": { + "assetId": { + "description": "Library audio asset id (list_bumpers, kind audio); the same asset can be used more than once", + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "duck": { + "description": "Lower the music while someone speaks (default true)", + "type": "boolean" + }, + "end": { + "description": "Music stops after this second of the source video", + "minimum": 0, + "type": "number" + }, + "fade": { + "description": "Fade in and out, seconds (default 0.5)", + "maximum": 5, + "minimum": 0, + "type": "number" + }, + "id": { + "description": "Stable id for this track (any short string; keep it when editing)", + "maxLength": 40, + "minLength": 1, + "type": "string" + }, + "loop": { + "description": "Repeat the track when it is shorter than the window (default true)", + "type": "boolean" + }, + "offset": { + "description": "Seconds into the track to start from (default 0)", + "minimum": 0, + "type": "number" + }, + "start": { + "description": "Music starts at this second of the source video", + "minimum": 0, + "type": "number" + }, + "volume": { + "description": "Music level 0-1 (default 0.6) on a track normalised to -20 LUFS, before ducking", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "id", + "assetId", + "start", + "end" + ], + "type": "object" + }, + "maxItems": 10, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Background music tracks under parts of the clip (max 10; the same asset may repeat): library audio assets (list_bumpers, kind audio), each with a window in source seconds, volume, ducking under speech, fades. Replaces the list; null or [] = none" +} - changed
Input schema / properties / layoutSections / anyOfPrevious 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" - } -]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 (top) crop sideways by this fraction of the source width (-0.5 to 0.5), relative to the face it follows", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetX2": { + "description": "Split only: shift the bottom crop sideways (-0.5 to 0.5)", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetY": { + "description": "Shift the (top) crop up or down by this fraction of the source height; only matters where the crop is shorter than the frame (split, stack)", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "offsetY2": { + "description": "Split only: shift the bottom crop up or down (-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" + }, + "subjectX": { + "description": "Follow the person at this x (0-1 of the source width) in the top/only pane; the offset still applies on top", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "subjectX2": { + "description": "Split only: follow the person at this x in the bottom pane", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "start", + "end", + "mode" + ], + "type": "object" + }, + "maxItems": 50, + "type": "array" + }, + { + "type": "null" + } +] - added
Input schema / properties / overlaysAdded value: +{ + "anyOf": [ + { + "items": { + "properties": { + "assetId": { + "description": "asset: library asset id (list_bumpers), an image or a video", + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "box": { + "description": "text: dark plate behind the text (default: outlined text, no plate)", + "type": "boolean" + }, + "color": { + "description": "text: colour as #RRGGBB, default white", + "pattern": "^#[0-9a-fA-F]{6}$", + "type": "string" + }, + "end": { + "description": "Hidden after this second of the source video", + "minimum": 0, + "type": "number" + }, + "font": { + "description": "text: font family from TEXT_FONTS (default DejaVu Sans, the caption font)", + "maxLength": 60, + "minLength": 1, + "type": "string" + }, + "id": { + "description": "Stable id for this overlay (any short string; keep it when editing)", + "maxLength": 40, + "minLength": 1, + "type": "string" + }, + "kind": { + "description": "asset (default): a library image or video; text: a line of text", + "enum": [ + "asset", + "text" + ], + "type": "string" + }, + "opacity": { + "description": "0.1-1, default 1", + "maximum": 1, + "minimum": 0.1, + "type": "number" + }, + "size": { + "description": "text: font size as a fraction of the output height (0.02-0.12), default 0.045", + "maximum": 0.12, + "minimum": 0.02, + "type": "number" + }, + "start": { + "description": "Shown from this second of the source video", + "minimum": 0, + "type": "number" + }, + "text": { + "description": "text: the line to show (1-120 chars)", + "maxLength": 120, + "minLength": 1, + "type": "string" + }, + "w": { + "description": "asset: width, fraction of the output width (0.05-1); the height follows the file. Default 0.3", + "maximum": 1, + "minimum": 0.05, + "type": "number" + }, + "x": { + "description": "Centre, fraction of the output width (0-1)", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "y": { + "description": "Centre, fraction of the output height (0-1)", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "required": [ + "id", + "start", + "end", + "x", + "y" + ], + "type": "object" + }, + "maxItems": 20, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Things laid over the clip for a time range (max 20): kind asset = a library image/video (list_bumpers; logos, stickers, b-roll), kind text = a line of text (size, color, box). Replaces the list; null or [] = none" +}
- Changed
update_project4 fields changed- added
Input schema / properties / settings / properties / disfluencyLlmAdded value: +{ + "description": "Model pass on top of rule-based disfluency detection. Off by default (rules only when disfluency is on).", + "type": "boolean" +} - added
Input schema / properties / settings / properties / refineDisfluencyAdded value: +{ + "description": "Find fillers, repetitions and false starts. Off by default; on runs that refine step.", + "type": "boolean" +} - added
Input schema / properties / settings / properties / refineEntitiesAdded value: +{ + "description": "Fix misheard names after transcription (LLM). Off by default; on runs that refine step.", + "type": "boolean" +} - added
Input schema / properties / settings / properties / refineScenesAdded value: +{ + "description": "Detect scene cuts and on-screen text. Off by default; on runs that refine step.", + "type": "boolean" +}
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 84 tools
Most tools have clearly distinct resource/action targets, and descriptions explicitly cross-reference alternatives such as delete_clip vs delete_clips and rerender_clip vs rerender_clips. Still, with 84 tools there are several near-neighbor pairs (update_clip/update_project_style, set_default_bumper/set_project_bumpers/set_clip_bumpers, delete_asset/purge_asset/restore_asset) that require careful reading to avoid misselection.
The surface is predominantly snake_case verb_noun (list_projects, create_clip, delete_webhook, restore_asset), which is predictable. A few names deviate into noun phrases or non-verb forms (billing_portal_url, billing_checkout_url, asset_usage), but these are minor exceptions rather than a mixed convention.
Eighty-four tools is far beyond the 3-15 well-scoped range and exceeds even the 50+ threshold for extreme mismatch. The domain is complex, but the surface is so large that discovery and correct selection become burdensome for an agent.
Coverage is unusually comprehensive: projects, clips, transcripts, assets, templates, webhooks, billing, admin, decisions, restore/purge lifecycle, and exports are all represented. The main gap is the lack of a first-class file-upload tool, since create_project/add_asset rely on an external POST /api/upload flow or an already-created uploadId.
Maintenance
Related MCP Connectors
Turn a long video into short vertical clips: find moments, add captions, reframe, export.
Long video in, captioned vertical clips out: clip, dub, transcribe and auto edit videos
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.
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
- AlicenseAqualityBmaintenanceOpenShorts turns long videos into vertical clips readys for Social Media posting87,529MIT
- FlicenseNot gradedqualityNot gradedmaintenanceEnables autonomous shortform video editing by converting 16:9 footage to 9:16 with dynamic speaker tracking, smart reframing bounding boxes, audio silence pacing, and precise cut-list generation through MCP-compatible clients.-