calesthio/twelvelabs-video-understanding
>- indexing footage, semantic/visual search across an archive, generating descriptions, summaries, chapters, highlights, and tags from video, producing multimodal embeddings, or wiring TwelveLabs into a media-production pipeline (NLE panels, logging, compliance review, metadata). Covers the current model families (Marengo for search/embeddings, Pegasus for video-to-text analysis), the v1.3 Video Understanding API (indexes, assets, tasks, search, analyze, embed), prompt construction for analysis, capability and format limits, pricing/quota math, output quality review (hallucination and timestamp accuracy), and privacy/rights obligations when footage shows real people. Not for generating or editing video pixels — this is analysis and retrieval.
npx skills add https://github.com/calesthio/generative-media-skills --skill twelvelabs-video-understanding
TwelveLabs builds video foundation models that read footage the way a human editor does — across visuals, on-screen text, motion, sound, speech, and music — and expose that understanding through a REST API, SDKs (Python, Node), an MCP server, and NLE plugins. This skill is for driving that platform to log, search, describe, segment, and tag video for production work. It is not a video *generator*; TwelveLabs does not synthesize or edit pixels.
All volatile facts below carry a verification date. Everything moves fast here — re-verify model names, limits, and pricing against docs.twelvelabs.io before quoting them to a user as current.
Reach for TwelveLabs when the job is any of:
Do not use it to create video, apply visual effects, transcode, or as a general speech-to-text tool (it does speech *understanding* for search/analysis, but a dedicated ASR is cheaper if plain transcripts are all you need).
*[Documented — docs.twelvelabs.io/docs/concepts/models, verified 2026-07-10]*
TwelveLabs is not one model. Pick by task:
| | Marengo | Pegasus |
|---|---|---|
| Purpose | Search + embeddings (retrieval) | Analysis + text generation |
| Output | Ranked video segments; vectors | Natural-language / structured text |
| Current version | Marengo 3.0 (GA Nov 2025) | Pegasus 1.5 (Apr 2026); 1.2 still available |
| You call it via | /search, /embed | /analyze |
| Modalities read | visual, audio, on-screen text/OCR, logos, speech, music | visual, audio, speech, on-screen text |
Rule of thumb: if the answer is *"which moments/videos?"* → Marengo (search). If the answer is *"tell me / describe / summarize / extract"* → Pegasus (analyze). Embeddings for your own vector DB → Marengo (embed). An index can enable one or both; enable only what you'll use, because each model you enable is billed at index time.
start_time/end_time), and a much larger context window.max_tokens./analyze endpoint accepts clips up to 1 hour; longer content uses the async analyze task.*[Documented — base https://api.twelvelabs.io, version v1.3, verified 2026-07-10]*
Everything hangs off an index. An index is a collection of videos configured with the model(s) that will process them.
Index ──► Asset / video upload ──► Indexing task (async) ──► ready video
│
┌────────────────────────────────────────────────┤
▼ ▼ ▼
/search (Marengo) /analyze (Pegasus) /embed (Marengo)
Configure which models are enabled and which modalities each analyzes. Enabling Marengo makes videos searchable; enabling Pegasus makes them analyzable. Enable both only if you need both.
Two paths, both real as of 2026-07-10:
POST /v1.3/tasks with index_id and either video_url (public URL up to 4 GB) or video_file (local, up to 2 GB; larger via the Multipart Upload API, up to 10 GB). Optional enable_video_stream (default true; stores an HLS proxy) and user_metadata (JSON of string/int/float/bool tags — set these at upload so you can filter searches later). Returns a task _id and the video_id.POST /assets to register the media, then POST /indexes/{index-id}/indexed-assets to index it. This separates "the file exists" from "index it into this index," which is cleaner when the same asset feeds multiple indexes. *[Documented; the docs mark the single-call /tasks route as the older pattern — verified 2026-07-10. Confirm which your SDK version defaults to.]*Indexing is asynchronous. Poll task status until ready (other states seen include validating, pending, indexing, and failed). SDKs offer task.wait_for_done() so you don't hand-roll the poll loop. Processing takes real wall-clock time — plan for minutes per video, more for long footage; never assume a just-uploaded video is immediately searchable.
POST /v1.3/searchsearch_options: which modalities to match — visual and/or audio. Combine with operator: "or" (default, broader recall) or "and" (both must match, higher precision).transcription_options: lexical, semantic, or both — controls whether spoken-word matching is exact-phrase or meaning-based.video_id, start/end (seconds), a relevance score/confidence, and rank (1 = best). Use the confidence tier and your own threshold to decide what's worth surfacing to an editor; low-confidence hits are candidates, not answers.POST /v1.3/analyzeThe single generative endpoint since /gist and /summarize were removed on 2026-02-15. /analyze produces *any* text you prompt for — summaries, chapter lists, action items, shot logs, compliance memos — and can return structured JSON via response_format (a JSON schema).
Key parameters *[Documented, verified 2026-07-10]*:
| Parameter | Notes |
|---|---|
| video / video_id | source: asset id, direct URL, or base64; video_id for pre-indexed (Pegasus 1.2 path) |
| prompt | the instruction |
| prompt_v2 | structured prompt with reference images (Pegasus 1.5) |
| temperature | 0–1, default 0.2 — keep low for factual logging/compliance |
| max_tokens | 512–98,304 (1.5); 2–4,096 (1.2) |
| stream | NDJSON streaming, default true (stream_start → text_generation → stream_end) |
| response_format | JSON schema for deterministic structured output |
| start_time/end_time | analyze only a clip (1.5) |
Synchronous for clips ≤ 1 hour; for longer video or batch, use the async analyze task (batch supports up to 1,000 requests per call).
*[Documented, verified 2026-07-10]* Two endpoints: a synchronous one for text, image, audio, and video under 10 minutes; an asynchronous one for audio/video up to 4 hours. Async flow: embed.v_2.tasks.create → poll retrieve (processing → ready) → read vectors from data. Per-media pricing (see below). Store vectors in your own DB (Qdrant, Elastic, pgvector, etc.) — TwelveLabs gives you the embeddings; you own the index.
Analysis quality is mostly a prompting problem. Heuristics below are production practice, not vendor guarantees.
*[Heuristic]*
response_format with an explicit JSON schema and fixed enums. Free prose is for humans; JSON is for pipelines.Intent: auto-log a 30-min interview reel so an assistant editor can populate bins.
Model: Pegasus 1.5, temperature: 0.2, response_format = schema below.
Prompt:
Log this interview footage for an editor. For each distinct segment, report:
the speaker (or "unknown"), the topic in <=8 words, whether the shot is a
close-up/medium/wide, and any on-screen lower-third text you can read verbatim.
Ignore color bars, slates, and dead air. If you cannot read text, use null —
do not guess names.
response_format schema (abridged):
{ "type": "object", "properties": { "segments": { "type": "array", "items": {
"type": "object",
"properties": {
"start": {"type":"number"}, "end": {"type":"number"},
"speaker": {"type":["string","null"]},
"topic": {"type":"string"},
"shot_size": {"type":"string","enum":["close-up","medium","wide"]},
"lower_third": {"type":["string","null"]}
}, "required": ["start","end","topic","shot_size"] } } } }
Why: enums keep shot_size clean; null instead of a guessed name curbs hallucinated identities; the "verbatim / do not guess" instruction is the main defense against confident fabrication.
Likely failure modes: invented lower-third names (mitigated by the null rule), timestamps drifting by 1–3 s (verify against search before cutting), over-segmentation of a single continuous shot.
Variation: add "brand_logos": {"type":"array"} to double as a brand-safety pass, or drop response_format and ask for a prose synopsis for a producer.
Intent: pull every moment a specific product appears, for a sizzle reel.
Model: Marengo 3.0 search (not analyze — you need real segment boundaries).
Request shape:
POST /v1.3/search
index_id: <reel_index>
query_text: "close-up of the blue running shoe, product clearly visible"
search_options: ["visual"]
operator: "and" # tighten precision; drop to "or" if recall is low
threshold / page_limit applied client-side on the returned score
Why visual-only + and: the target is a visual object, audio is irrelevant, and precision matters more than catching every borderline frame in a highlight reel.
Expected result: ranked segments with usable start/end you can push straight to a timeline (this is exactly what the Premiere plugin does under the hood).
Failure modes: the model matches similar-looking shoes (add an image query of the actual product to disambiguate — combined text+image is far stronger for a specific SKU); very brief appearances rank low (lower your threshold and review manually).
*[Documented, verified 2026-07-10]*
*[Documented unless marked]*
wait_for_done in; surface "processing" state to users./gist and /summarize gone (2026-02-15); Marengo 2.7 sunset (2026-03-30); cloud-to-cloud integrations deprecated (2025-10-31). Old tutorials will reference dead endpoints.*[Documented — Developer (pay-as-you-go) plan, twelvelabs.io/pricing, verified 2026-07-10. Re-verify before quoting; use the official pricing calculator for a real estimate.]*
| Operation | Price |
|---|---|
| Video indexing (one-time) | $0.042 / min |
| Storage/infra (monthly) | $0.0015 / min |
| Search API | $4 / 1,000 queries |
| Analyze — input video (Pegasus 1.5) | $0.0292 / min (1.2: $0.021/min) |
| Analyze — output text | $0.0075 / 1,000 tokens |
| Embed — video | $0.042 / min |
| Embed — audio | $0.0083 / min |
| Embed — image | $0.10 / 1,000 requests |
| Embed — text | $0.07 / 1,000 requests |
Worked estimate *(illustrative, 2026-07-10 rates)*: index 100 hours of footage once = 6,000 min × $0.042 ≈ $252 one-time, + ~$9/mo storage. Then 1,000 searches ≈ $4. A summary of a 20-min clip: 20 × $0.0292 (input) + ~2k output tokens × $0.0075/1k ≈ $0.60/clip. The cost driver in a logging pipeline is usually analyze input-minutes, not output tokens — analyze only the clips you must, and prefer *search* (per-query pricing) for pure retrieval.
Rate limits are multi-dimensional (separate video/audio/image/text budgets) and tiered by monthly spend; you start at Tier 1 on adding a payment method and auto-upgrade with spend, with a one-month grace period on downgrade. Exact RPM per tier isn't published as a stable figure — read 429 headers and back off rather than hard-coding assumptions. *[Documented structure; exact numbers not fixed — verified 2026-07-10.]*
Never ship model output unreviewed. Two failure classes dominate:
1. Hallucination in generative (Pegasus) output *[Heuristic]*
Summaries and logs can state confident, plausible, wrong facts — invented names, misattributed quotes, events that didn't happen. Defenses: low temperature; "do not guess / use null" instructions; ask for evidence anchors (verbatim on-screen text, described sounds) so a reviewer can spot-check; keep prompts single-purpose. For anything with legal, compliance, or publication weight, a human verifies against the footage — treat Pegasus as a fast first-pass logger, not a source of record.
2. Timestamp accuracy *[Heuristic + documented limits]*
Times Pegasus writes *into prose* are approximate and can drift a few seconds — fine for a producer's chapter list, not for a frame-accurate cut. When boundaries must be right, get them from Marengo search results (start/end), which are the model's actual segment detections, and confirm on the timeline. Search confidence is a real signal: set a threshold, treat sub-threshold hits as leads to review, not results.
Also review: completeness (did it miss a segment? long video + small max_tokens truncates silently — check finish_reason), language coverage (36+ languages, but verify non-English speech matching on a sample), and false positives in brand/compliance search (visually similar ≠ the actual logo/product; confirm with an image query).
*[Documented — twelvelabs.io/privacy-policy — plus production obligation, verified 2026-07-10]*
Indexing footage of real people creates biometric-adjacent processing (faces, voices, identifiable individuals). TwelveLabs' policy makes the customer responsible for having a lawful basis and appropriate consent for the personal data they put through the service; TwelveLabs acts as processor and supports data-subject rights (access, correction, deletion, portability) for EEA/UK individuals.
Before indexing footage of identifiable people, the agent should:
When a user asks to index or search footage of real people they may not have rights to, surface the consent/rights question rather than silently proceeding.
*[All verified 2026-07-10]*
https://docs.twelvelabs.io/docs/concepts/models, /models/marengo, /models/pegasushttps://docs.twelvelabs.io/docs/get-started/release-noteshttps://docs.twelvelabs.io/api-reference/introduction, /docs/guides/search, /api-reference/analyze-videos/analyze, /api-reference/create-embeddings-v2https://docs.twelvelabs.io/api-reference/upload-content/tasks/createhttps://www.twelvelabs.io/pricing, https://docs.twelvelabs.io/docs/get-started/rate-limitshttps://docs.twelvelabs.io/docs/resources/partner-integrations/adobe-premiere-pro-pluginhttps://docs.twelvelabs.io/docs/advanced/model-context-protocol, https://www.twelvelabs.io/blog/twelve-labs-mcp-serverhttps://press.aboutamazon.com/aws/2025/12/twelvelabs-launches-its-most-powerful-video-understanding-model-marengo-3-0-on-twelvelabs-and-amazon-bedrockhttps://www.twelvelabs.io/privacy-policyhttps://github.com/twelvelabs-io/twelvelabs-pythonTake calesthio/twelvelabs-video-understanding from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.