npx skills add ...
npx skills add video-db/skills --skill videodb
See, Understand, Act on video and audio. See- ingest from local files, URLs, RTSP/live feeds, or live record desktop; return realtime context and playable stream links. Understand- run analyzers over speech, scenes, objects, OCR, brands and activity; build searchable indexes; then search moments, ask questions about a video, filter and aggregate results with timestamps and auto-clips. Act- transcode and normalize (codec, fps, resolution, aspect ratio), perform timeline edits (subtitles, text/image overlays, branding, audio overlays, dubbing, translation), generate media assets (image, audio, video), and create real time alerts for events from live streams or desktop capture.
npx skills add video-db/skills --skill videodb
Perception + memory + actions for video, live streams, and desktop sessions.
Use this skill when you need to:
https://console.videodb.io/player?url={STREAM_URL}CRITICAL: Always cd to the user's project directory before running Python code. This ensures load_dotenv(".env") finds the correct .env file.
This reads VIDEO_DB_API_KEY from:
.env file in current directoryIf the key is missing, videodb.connect() raises AuthenticationError automatically.
Do NOT write a script file when a short inline command works.
When writing inline Python (python -c "..."), always use properly formatted code — use semicolons to separate statements and keep it readable. For anything longer than ~3 statements, use a heredoc instead:
When the user asks to "setup videodb" or similar:
If videodb[capture] fails on Linux, install without the capture extra:
The >=0.5.0 pin matters — the understand/index/ask/aggregate APIs do not exist in earlier versions.
The user must set VIDEO_DB_API_KEY using either method:
export VIDEO_DB_API_KEY=your-key.env file: Save VIDEO_DB_API_KEY=your-key in the project's .env fileGet a free API key at https://console.videodb.io (50 free uploads, no credit card).
Do NOT read, write, or handle the API key yourself. Always let the user set it.
The plugin bundles the hosted MCP server at https://mcp.videodb.io/mcp, which is
authorized separately from the SDK key above. Tell the user to run /mcp, select
videodb, and complete browser authorization with their VideoDB account. Verify with
"list my VideoDB collections".
The MCP tools need no local Python install and no API key. Skip this step when the skill
was installed with npx skills add or is running outside Claude Code — there is no MCP
server in that case, and the SDK path above is the only one available.
Three stages. Run analyzers to produce artifacts, index each artifact, then retrieve.
Analyzer types: spoken_words (→ artifact transcript), vlm (→ scene), object_detection (→ objects), ocr, brand_detection (→ brands), activity_recognition (→ activity), location_detection (→ location), faces, audio_event_detection. They are plain strings — there is no SDK enum.
See reference/indexing.md for segmentation, sampling, field configuration, and cost tuning.
search(query) is the default — it plans the retrieval and picks the indexes itself. Reach past it when you need something specific:
All five exist on Collection too, fanning out across every indexed video. See reference/search.md.
search() now returns SearchResponse, not SearchResult. get_shots(), compile(), play(), and iteration all work, but there is no .stream_url on it — use .compile().
index_spoken_words() is the correct call here even on 0.5.0 — add_subtitle() and CaptionAsset(src="auto") read the v1 spoken-word index. A v2 spoken_words artifact does not substitute for it. This is the one place v1 indexing is still the right answer.
Recognise this pattern in existing repos and leave it alone unless asked to migrate — it still works. See reference/migration.md to port it, or reference/legacy/search.md to maintain it.
Use the Editor API to compose videos, images, audio, and text. See reference/editor.md for full workflow.
Warning: reframe() is a slow server-side operation. For long videos it can take
several minutes and may time out. Best practices:
start/end when possiblecallback_url for async processingTimeline first, then reframe the shorter resultRun open-weight models (Gemma, Qwen, Whisper, OmniVoice, FLUX, RT-DETR) by creating a sandbox and passing sandbox_id to a supported job. Requires videodb>=0.5.1.
Model IDs must match the catalog exactly (no -FP8 suffix) or create_sandbox raises Unsupported sandbox model. See reference/sandbox.md for the full model catalog, tiers, categories, pricing, and pitfalls.
| Scenario | Error message | Solution |
|---|---|---|
| Search result has no stream URL | AttributeError: 'SearchResponse' object has no attribute 'stream_url' | search() returns SearchResponse in 0.5.0. Use results.compile() |
search(score_threshold=) searches the wrong indexes | no error, unexpected results | score_threshold does not route to legacy. Use semantic_search(score_threshold=), or legacy_search() for v1 indexes |
| Semantic index on object detection | use_for includes semantic but no scene has embeddable text | Object artifacts have no top-level text. Omit use_for (it degrades automatically) or pass ["query", "aggregate"] |
| Indexing a field that does not exist | fields.filter names not present in any scene's data | The error lists the available field names — read it. Or check index.field_schema |
| Search finds no matches | v2 returns an empty SearchResponse; only legacy_search() raises InvalidRequestError: No results found | Check len(response). Wrap only legacy calls in try/except |
| Indexing an already-indexed video (v1) | Spoken word index for video already exists | Use video.index_spoken_words(force=True) to skip if already indexed |
| Reframe times out | Blocks indefinitely on long videos | Use start/end to limit segment, or pass callback_url for async |
| Negative timestamps on Timeline | Silently produces broken stream | Always validate start >= 0 before creating VideoAsset |
generate_video() / create_collection() fails | Operation not allowed or maximum limit | Plan-gated features — inform the user about plan limits |
Reference documentation is in ${CLAUDE_SKILL_DIR}/reference/. Read files there with that prefix; the links below are relative to this SKILL.md.
Legacy v1 indexing and search. These APIs still work and are not deprecated, but read these only when maintaining existing v1 code:
Use ws_listener.py to capture WebSocket events during recording sessions. Desktop capture supports macOS only.
${CLAUDE_SKILL_DIR} is this skill's install directory, set by Claude Code. On agents that do not set it, substitute the directory holding this SKILL.md.
python "${CLAUDE_SKILL_DIR}/scripts/ws_listener.py" --cwd=<PROJECT_ROOT> &cat /tmp/videodb_ws_id/tmp/videodb_events.jsonl${CLAUDE_SKILL_DIR}/scripts/ws_listener.py - WebSocket event listener (dumps to JSONL)For complete capture workflow, see reference/capture.md.
Do not use ffmpeg, moviepy, or local encoding tools when VideoDB supports the operation. The following are all handled server-side by VideoDB — trimming, combining clips, overlaying audio or music, adding subtitles, text/image overlays, transcoding, resolution changes, aspect-ratio conversion, resizing for platform requirements, transcription, volume control, fade transitions, and media generation. Only fall back to local tools for operations listed under Limitations in reference/editor.md (speed changes, crop/zoom, colour grading, keyframe animation).
| Problem | VideoDB solution |
|---|---|
| Make a video searchable | video.understand(analyzers=[...]) then video.index(source=analyzer) |
| Find moments by what was said or shown | video.search(query), or semantic_search(index_names=[...]) to target an index |
| Answer a question about a video | video.ask(question, include_sources=True) |
| Count or group what appears in a video | video.aggregate(index_name=..., group_by=..., metric="count") |
| Filter moments on exact field values | video.query(index_name=..., filter={...}) |
| Platform rejects video aspect ratio or resolution | video.reframe() or conn.transcode() with VideoConfig |
| Need to resize video for Twitter/Instagram/TikTok | video.reframe(target="vertical") or target="square" |
| Need to change resolution (e.g. 1080p → 720p) | conn.transcode() with VideoConfig(resolution=720) |
| Need to overlay audio/music on video | AudioAsset on an Editor Timeline with volume control |
| Need to add subtitles | video.add_subtitle() or CaptionAsset on Editor Timeline |
| Need to combine/trim clips | VideoAsset on an Editor Timeline |
| Need to compose images with voiceover | ImageAsset + AudioAsset on separate Editor tracks |
| Need to generate voiceover, music, or SFX | coll.generate_voice(), generate_music(), generate_sound_effect() |