# Docs

> DaVinci Resolve MCP Server — AI Skill Reference

- Skill: `hybridlabor-api/docs` (Agent Skill, multi-file: 63 files)
- Install (CLI): `npx skillmds@latest add hybridlabor-api/docs`
- Raw SKILL.md: https://api.skillmd.com/api/skills/hybridlabor-api/docs/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: hybridlabor-api (https://skillmd.com/u/hybridlabor-api)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/hybridlabor-api/docs

---

# DaVinci Resolve MCP Server — AI Skill Reference

This document gives AI assistants the context needed to use the DaVinci Resolve
MCP server effectively. It covers the tool landscape, page prerequisites,
common workflow patterns, error recovery, and known gotchas.

---

## What This Server Does

The DaVinci Resolve MCP server bridges AI assistants to DaVinci Resolve Studio
via its official Scripting API. You can control every aspect of a post-production
session — projects, timelines, clips, color grading, Fusion compositions, audio,
render queues, and more — through natural language.

DaVinci Resolve must be running with **Preferences > General > "External scripting
using"** set to **Local**. The server auto-launches Resolve if it is not running,
but that first connection can take up to 60 seconds.

Workflow Integration plugins/scripts are a separate Resolve-hosted UI mechanism.
They are not required for this MCP server, but `docs/integrations/workflow-integrations.md`
summarizes when they are useful for optional in-Resolve panels, UIManager
scripts, and render callback companions.

OpenFX plugins are native C++ image-effect plugins, not an MCP control surface.
Use `docs/notes/openfx-notes.md` when diagnosing `insert_ofx_generator` failures or
discussing optional OFX plugin development.

LUT files are directly relevant to Color-page graph actions. Use
`docs/notes/lut-notes.md` when diagnosing `graph.set_lut` failures, validating `.cube`
files, or explaining `project_settings.refresh_luts`.

Fusion templates are relevant to Edit/Cut page insertion actions. Use
`docs/notes/fusion-template-notes.md` when diagnosing `insert_fusion_generator` or
`insert_fusion_title` failures, template paths, `.setting` files, or `.drfx`
bundles.

DCTL files are programmable color transforms/effects adjacent to LUT and OpenFX
workflows. Use `docs/notes/dctl-notes.md` when diagnosing `.dctl`/`.dctle` discovery,
ResolveFX DCTL plugin behavior, ACES DCTL IDT/ODT setup, or DCTL-as-LUT usage.

Codec plugins are native IO encode plugins that extend Deliver-page render
formats/codecs. Use `docs/notes/codec-plugin-notes.md` when diagnosing missing custom
render formats/codecs, `.dvcp.bundle` packaging, or IOPlugins install paths.

The `fuse_plugin`, `dctl`, and `script_plugin` compound tools (v2.5.0+) write
Fuse plugin source, DCTL files, and Lua/Python scripts into Resolve's install
directories. They are *authoring* tools — every other tool in this server wraps
Resolve's scripting API, while these three emit and install plugin/script
source. Status: lifecycle-verified in DaVinci Resolve Studio 20.3.2.9 for
MCP-marked install/read/list/remove, regular DCTL `refresh_luts`, ACES/Fuse
restart-required classification, Python installed-script execution, and
Python/Lua `run_inline`. Use `docs/kernels/extension-authoring-kernel.md` for the
kernel boundary map, `docs/authoring/fuse-dctl-authoring.md` for the Fuse + DCTL coverage
matrix, and `docs/authoring/script-plugin-authoring.md` for the script DSL spec and the
conversational-execution model. For hand-authoring `.setting` template files
(Edit effects/transitions/titles/generators and Fusion macros) — the format,
control catalog, thumbnail conventions, install paths, and gotchas, plus copyable
starter templates — see `docs/authoring/setting-files/`.

Extension Authoring kernel actions (v2.16.0+) are exposed through
`script_plugin`:

- `extension_capabilities`
- `probe_fuse_lifecycle(name?, kind?, install?, cleanup?)`
- `probe_dctl_lifecycle(name?, kind?, category?, install?, refresh_luts?, cleanup?)`
- `probe_script_lifecycle(name?, language?, category?, install?, execute?, cleanup?)`
- `safe_install_extension(extension_type, name, source?|kind?, dry_run?)`
- `safe_remove_extension(extension_type, name, dry_run?)`
- `refresh_or_restart_required(extension_type, category?)`
- `extension_boundary_report(include_template_matrix?)`

Key behavioral notes for `script_plugin`:
- `run_inline(source, language)` runs ad-hoc Lua/Python in Resolve and returns
  stdout + result — use this for one-off conversational queries against the
  Resolve API instead of building+installing a script.
- `language` accepts `lua`, `py`, or the human-facing aliases `python` and
  `python3`.
- `execute(name, category, language)` runs an installed script; Python stdout
  and stderr are captured, while installed Lua execution can return false from
  the Python bridge even when install/read/list/remove worked.
- Lua scripts: `fusion.Execute()` from the Python bridge is a no-op in
  Resolve 20.x — `_run_inline_lua` works around this with `RunScript` against
  a temp file plus completion-sentinel polling on `app:SetData/GetData`.
- Fuse install path on macOS is `…/DaVinci Resolve/Fusion/Fuses/` (NOT
  `Support/Fusion/Fuses/` as the SDK doc lists). The MCP path helpers handle
  this; if you're staging files manually, use the path the implementation
  emits.
- Resolve picks up new scripts without a restart; new Fuses need a restart
  to register; new DCTLs need `project_settings(action='refresh_luts')`
  (regular LUT category) or a restart (ACES IDT/ODT category).

Tool metadata (v2.17.1+) includes MCP `ToolAnnotations` for read-only,
destructive, idempotent, and external-resource hints. Treat compound tool
annotations as conservative because a single compound tool may expose both probe
and mutation actions behind its `action` parameter. Continue to prefer
`safe_*`, `dry_run`, `probe_*`, `capabilities`, and `boundary_report` actions
before mutating Resolve state.

---

## Two Server Modes

| Mode | Entry point | Tool count | Use when |
|---|---|---|---|
| Compound (default) | `src/server.py` | 32 tools | Most workflows — keeps context lean |
| Granular (full) | `src/server.py --full` | 341 tools | Power users needing one tool per API method |

This skill document covers the **compound server** (the default). Each compound
tool accepts an `action` string and an optional `params` object.

The compound server also registers MCP prompts. Use `davinci_resolve_workflow`
as the compact operating brief, and use `analyze_media` as a slash-command style
entry point for source-safe project, selected-clip, bin, file, or sequence
analysis. The Analyze Media prompt executes directly by default, persists
inspectable reports/artifacts under the project analysis root, requests
`host_chat_paths` visual analysis (frames are extracted to disk and the host
chat finalizes each clip via `media_analysis(action="commit_vision", ...)`),
runs local transcription through the configured backend, and writes metadata
plus source-time Media Pool markers back to the Resolve project unless the
user opts out.

Anti-regression rule: do not silently downgrade media analysis. Source-safe
means source media stays untouched; it does not mean no visuals, no transcript,
no persisted report, no metadata writeback, or no Media Pool markers. Do not
add `include_visuals=false`, `include_transcription=false`,
`publish_metadata=false`, `timed_markers=no`, `session_only=true`, or
`dry_run=true` unless the user explicitly asks for that opt-out, the target is a
raw file path that cannot receive Resolve project writeback. The host_chat_paths
vision protocol is: `analyze_*` returns a deferred payload with absolute
`frame_paths` and a JSON schema; you must read those frames as images (Claude
Code's Read tool handles JPG/PNG natively), produce the JSON, and call
`commit_vision` for each clip. Skipping `commit_vision` leaves the run in
`pending_host_vision_analysis` — surface that explicitly; do not call the
analysis complete.

The deferred payload also includes a `host_tool_choice_hint` block. Hosts that
respect this hint pass it as `tool_choice={type:"tool", name:"media_analysis"}`
on the next API turn, hard-locking the agent into the correct next call. Hosts
that don't recognize the field ignore it — the flow is unchanged for them.

## Local Control Panel

If the user asks to open, launch, or inspect the Resolve MCP control panel, run
this from the repository root:

```bash
venv/bin/python -m src.control_panel
```

The command starts the local control panel and opens the default browser. Use
`--no-open` when running in a headless context, then give the user the printed
localhost URL. The panel is local and single-user; it is an operational surface
for server status, Resolve clips, source-safe analysis jobs, preferences, and
diagnostics as those sections are added.

The **Review tab → History** button opens the timeline-history surface:
per-timeline version chain, brain-edit deltas, manual archive, and rollback.
Backed by `timeline_versioning` MCP actions; see that tool's section below for
the underlying primitives.

---

## Editorial Memory And Decision-Making

When the user asks for cutting, pacing, story shape, suspense, comedy timing, or
tonal reframing, operate like an editor, not just a metadata scanner. Use
`docs/guides/editorial-decision-guide.md` as the project-owned craft reference. The
short version: emotion and story come first, then clarity, rhythm, eye trace,
screen geography, continuity, and coverage variety.

Before analyzing or rebuilding anything, check whether the active project already
contains useful evidence:

- `media_analysis(action="coverage_report", params={"target": {...}})` — the
  pre-flight contract. Pure read; never triggers analysis. Returns per-clip
  state (analyzed / stale / missing / reuse_blocked / superseded_by_relink),
  layer presence, `source_trust` tier, and a `recommended_action`. The response
  carries an `evidence_base` summary string — **lead any editorial or color
  recommendation with that line, before the creative answer.**
- `media_analysis(action="summarize")` for project-wide rollup of warnings,
  motion distribution, and signed-report counts.
- `media_analysis(action="get_report")` when a manifest or report path is known.
- `timeline(action="list")`
- `timeline(action="get_current")`
- `timeline(action="probe_timeline_structure")`
- `timeline(action="source_range_report")`
- `timeline_markers(action="get_all")`
- `media_analysis(action="review_timeline_markers")` when marker imagery matters

Reuse prior analysis unless it is stale, incomplete, missing a modality, or
flagged `superseded_by_relink` because Resolve's source clip was replaced after
analysis ran. Coverage_report surfaces all of these in one read. Do not re-run
visual analysis just because the edit task is new if a current report already
has keyframes, motion variance, and usable visual descriptions. Add
transcription, host_chat_paths vision (followed by commit_vision), marker
review, or source range checks only when that missing evidence changes the
decision. Use `force_refresh=true` only when the user asks for a fresh read or
when cache signatures show the source, prompt, depth, or requested modality has
changed.

Source-trust filtering: `coverage_report` accepts `min_source_trust` (one of
`auto`, `filename`, `low`, `medium`, `high`). Clips below the threshold appear
in `summary.clips_needs_higher_trust` and are reported with
`below_min_source_trust=true`. Use `medium` for routine work, `high` for
shot-matching or look-development passes where confident scene/identity reads
matter.

For finished-video editorial work, scene detection and motion variance are
guardrails, not story. Use them to avoid black frames, flash frames, corrupt
ranges, and accidental cut points. Let transcript, sound events, complete
thoughts, reactions, and decisive visual frames drive the actual edit.

After creating or modifying a timeline variant, do a second pass before calling
the work done:

- `timeline(action="detect_gaps_overlaps")`
- `timeline(action="source_range_report")`
- `timeline_markers(action="get_thumbnail_image")` at important markers and cuts
- Compare each marker name against the Resolve-rendered frame; revise the marker
  or edit if the image contradicts the plan.

Do not depend on personal, external, or workstation-specific editorial context.
For this project, keep the editorial craft reference self-contained in
`docs/guides/editorial-decision-guide.md` and keep this `SKILL.md` focused on
operational use of the MCP.

---

## Color Memory And Decision-Making

When the user asks for color correction, shot matching, look development, LUTs,
DCTLs, DRX grades, Gallery stills, or color-group workflows, use
`docs/guides/color-decision-guide.md` as the project-owned color reference.

Be explicit about the API boundary:

- Directly creatable/control surfaces: CDL values on an existing node, grade
  versions, color-group assignment, LUT assignment on existing nodes, node
  enable/cache state, LUT/DCTL assets, Gallery still import/export, and grade
  copy/export helpers.
- Opaque full-grade surfaces: copied grades, imported/exported `.drx` stills,
  and manually built Resolve node graphs. These can carry full grades, but the
  MCP applies or copies them as packages.
- Not directly creatable from structured params: new node trees, Lift/Gamma/Gain
  wheel values, log/HDR palette values, curves, qualifiers, power windows,
  tracking, Color Warper, and detailed ResolveFX/OFX parameter edits.

Before any color recommendation, run
`media_analysis(action="coverage_report", params={"target": {...},
"min_source_trust": "medium"})` (use `"high"` for shot-matching or
look-development passes). Lead the response with the returned `evidence_base`
line before the grade plan. Coverage_report surfaces relink-superseded clips
that must be re-analyzed before being graded from prior visual descriptions.

For safe color work, start with `timeline_item_color(action="grade_boundary_report")`,
`timeline_item_color(action="grade_version_snapshot")`,
`timeline_item_color(action="probe_node_graph")`, and a Resolve-rendered frame
reference for the target shot or shots. Use thumbnails, contact sheets, Gallery
stills, marker frames, or existing visual analysis reports before writing a
grade, and cite the inspected frames in the response. When the API can safely
provide them, compare matched untreated/bypass, current, and after frames at the
same timecodes, then restore the previous active version or node-enabled state
after any temporary bypass capture. Treat untreated frames as diagnostic
evidence, not as permission to discard an existing creative grade.

Prefer `safe_set_cdl` for small reversible primary corrections. Use DRX/stills
or grade copy only when the user accepts whole-grade replacement/transfer
semantics. Use DCTL/LUT authoring only for reusable mathematical transforms, not
as a substitute for hand-built windows, qualifiers, or tracked secondaries. Do
not apply blind/global grades unless the user explicitly asks for that. When the
user asks to build on or adjust an existing grade, preserve the current
grade/version as the starting point, create or switch to a recoverable
adjustment version, and apply only incremental changes through supported
controls. Do not reset grades, replace graphs, or apply DRX/copy-grade
whole-grade artifacts unless replacement or transfer semantics are explicitly
accepted. Distinguish Resolve's default one-node graph from an existing creative
grade; only describe a creative grade when active tools, LUTs, or other grade
state are present.

For sequence-wide looks, prefer a duplicated timeline, batch creation of
reference/current/look versions across all target clips, and one bulk Resolve
script for repeated version, group, or CDL operations. Use color groups for shared
scene-level intent only when they fit the work: group pre-clip for shared
normalization, clip versions for shot-specific matching, and group post-clip for
the creative look. Sampling can guide a first pass, but final handoff should
state the reviewed scope; short sequences should be checked shot by shot.

---

## Page Context Requirements

DaVinci Resolve is a page-based application. Certain operations only work on
specific pages. Always confirm or switch pages before calling page-sensitive tools.

| Operation category | Required page | How to switch |
|---|---|---|
| Color grading, node graphs, CDL | Color | `resolve_control(action="open_page", params={"page": "color"})` |
| Gallery stills export, `grab_and_export` | Color, Gallery panel open | `resolve_control` + open Gallery panel in Workspace menu |
| Fusion compositions (page comp) | Fusion | `resolve_control(action="open_page", params={"page": "fusion"})` |
| Timeline editing, track operations | Edit or Cut | `resolve_control(action="open_page", params={"page": "edit"})` |
| Fairlight audio | Fairlight | `resolve_control(action="open_page", params={"page": "fairlight"})` |
| Render / deliver | Deliver | `resolve_control(action="open_page", params={"page": "deliver"})` |
| Media import, storage browsing | Media | `resolve_control(action="open_page", params={"page": "media"})` |

When a tool returns an unexpected `False` or an error about context, check whether
you are on the correct page first.

---

## Tool Map

### App Control

**`resolve_control`** — App-level operations.

Key actions:
- `launch` — connect to or start Resolve; call this first if any tool returns a
  "Not connected" error
- `get_version` — returns `{product, version, version_string}`
- `api_truth(query?)` — look up behaviorally-verified facts about quirky/unreliable
  Resolve API behavior (no connection needed); filter by substring
- `verification_stats` — readback-verification tally (verified/contradicted/
  unverified) since server start (no connection needed)
- `get_page` / `open_page(page)` — read or switch the active page
- `get_keyframe_mode` / `set_keyframe_mode(mode)`
- `get_fairlight_presets` — Resolve 20.2.2+; returns available Fairlight
  preset names
- `quit` — terminates Resolve (destructive; confirm with user first)

**`layout_presets`** — Save, load, export, import, delete UI layout presets.

**`render_presets`** — Import and export render and burn-in presets.

---

### Project Management

**`project_manager`** — CRUD on projects.

Key actions: `list`, `get_current`, `create(name, media_location_path?)`,
`load(name)`, `save`, `close`,
`delete(name)`, `import_project(path)`, `export_project(name, path)`, `archive`,
`restore`

Project / Database / Archive kernel actions (v2.15.0+) add guarded project
lifecycle, settings, database, preset, and archive boundary helpers:

- `project_capabilities`
- `probe_project_lifecycle`
- `probe_project_settings(keys?, try_write?, dry_run?)`
- `safe_project_create(name, media_location_path?, dry_run?)`
- `safe_project_export(name, path, with_stills_and_luts?, dry_run?)`
- `safe_project_import(path, name, dry_run?)`
- `safe_project_archive(name, path, src_media=false, render_cache=false, proxy_media=false, dry_run?)`
- `safe_project_restore(path, name, dry_run?)`
- `safe_project_delete(name, close_current?, dry_run?)`
- `safe_set_project_settings(settings, restore?, dry_run?)`
- `project_settings_snapshot(name?)`
- `database_capabilities`
- `safe_set_current_database(db_info, dry_run?, allow_switch?)`
- `preset_lifecycle_probe`
- `project_boundary_report`

Health check and declarative spec (v2.28.0+):

- `lint` — graded project health pre-flight returning `{ok, counts, issues}`.
  Issues (error / warning / info) cover: no project, no current timeline, mixed
  frame rates across timelines, empty timeline, render format unset, color
  science unmanaged, offline media, and unanalyzed clips. Composed from existing
  probes; safe read-only.
- `diff_to_spec(spec_path | spec)` — preview drift between a declarative spec and
  the live project WITHOUT mutating. Returns `{actions, diff, change_count}`.
- `plan_spec(spec_path | spec)` — the ordered action list as a dry run.
- `apply_spec(spec_path | spec, dry_run?, run_hooks?, continue_on_error?)` —
  reconcile the project toward the spec. Idempotent (re-runs are no-ops); color/
  HDR settings apply in dependency order; markers added only when absent; explicit
  `settings` override a named `color_preset`; before/after shell hooks run only
  with `run_hooks=true`. The spec is YAML or JSON:
  `{project, color_preset?, settings?, timelines:[{name, fps?, settings?, markers?}], hooks?}`.
  Note: `apply_spec` reconciles the **currently open or already-existing** project;
  creating a brand-new project from a spec depends on Resolve's `CreateProject`
  succeeding (it can return None when an unsaved project blocks the switch).

Safe project actions require `_mcp_` names and temp paths by default. Database
switching dry-runs by default because Resolve closes open projects when
switching databases. Archive source media/cache/proxy flags are rejected unless
explicitly opted in.

**`project_manager_folders`** — Navigate project folders.

Key actions: `list`, `get_current`, `create(name)`, `open(name)`, `goto_root`,
`goto_parent`

**`project_manager_database`** — Switch databases.

Key actions: `get_current`, `list`, `set_current(db_info)`

**`project_manager_cloud`** — Cloud projects (requires Resolve cloud
infrastructure; most users will not have this).

**`project_settings`** — Project metadata, settings, color groups, and misc
operations on the open project.

Key actions: `get_name`, `set_name(name)`, `get_setting(name?)`,
`set_setting(name, value)`, `get_color_groups`, `add_color_group(name)`,
`delete_color_group(name)`, `export_frame_as_still(path)`,
`load_burnin_preset(name)`, `insert_audio(media_path, ...)`,
`apply_fairlight_preset(preset_name)`,
`project_summary(include_clips?, clip_limit?)` — live structural readout
(current page, timeline count, media-pool inventory by type)

---

### Media

**`media_storage`** — Browse mounted volumes and import files.

Key actions: `get_volumes`, `get_subfolders(path)`, `get_files(path)`,
`import_to_pool(items)` — `items` is a list of file path strings

**`media_pool`** — Full Media Pool management.

Key actions: `get_root_folder`, `get_current_folder`, `set_current_folder(path)`,
`add_subfolder(name)`, `create_timeline(name)`, `import_timeline(path, options?)`,
`import_media(paths)`, `delete_clips(clip_ids)`, `move_clips(clip_ids, target_path)`,
`setup_multicam_timeline(name, clip_ids|angles, sync_mode?, include_audio?, dry_run?)`,
`get_selected`, `set_selected(clip_id)`, `export_metadata(path, clip_ids?)`

Media Pool / Ingest kernel actions (v2.8.0+) add safer agent-facing workflows:
`ingest_capabilities`, `probe_media_pool`, `probe_ingest_item`,
`safe_import_media`, `safe_import_sequence`, `safe_import_folder`,
`organize_clips`, `copy_metadata`, `normalize_metadata`,
`probe_clip_properties`, `metadata_field_inventory`, `safe_relink`,
`safe_unlink`, `link_proxy_checked`, `link_full_resolution_checked`,
`set_clip_marks`, `clear_clip_marks`, `copy_clip_annotations`,
`setup_multicam_timeline`, and
`media_pool_boundary_report`. See
`docs/kernels/media-pool-ingest-kernel.md` for the live-tested support map.

`setup_multicam_timeline` is a helper, not a native multicam API wrapper. It
creates a source-safe stacked prep timeline with one angle per video track,
optional matching audio tracks, and `stack_start`, `source_timecode`, or
explicit `record_frame` placement. Native multicam clip creation, angle
switching, and flattening remain Resolve UI workflows; see
`docs/guides/multicam-setup-guide.md`.

Note: `folder path` arguments use slash notation like `"Master/SubFolder"`.
`"Master"` or `"/"` refers to the root folder.

**`folder`** — Operations on a specific Media Pool folder.

Key actions: `get_clips(path?)`, `get_subfolders(path?)`, `export(path?, export_path)`,
`transcribe_audio(path?, use_speaker_detection?)`, `clear_transcription(path?)`,
`perform_audio_classification(path?)`, `analyze_for_intellisearch(path?, identify_faces?, is_better_mode?)`,
`analyze_for_slate(path?, marker_color?)`, `remove_motion_blur(path?, deblur_option?)` (Resolve 21+;
the last three need AI Extras, and `remove_motion_blur` is confirm-token gated)

**`media_pool_item`** — Read/write clip metadata and properties. All actions
require a `clip_id` (the UUID returned by `GetUniqueId()`).

Key actions: `get_name`, `get_metadata(key?)`, `set_metadata(key, value)`,
`get_clip_property(key?)`, `set_clip_property(key, value)`, `get_clip_color`,
`set_clip_color(color)`, `link_proxy(proxy_path)`, `replace_clip(path)`,
`set_name(name)`, `link_full_resolution_media(path)`,
`replace_clip_preserve_sub_clip(path)`, `monitor_growing_file`,
`transcribe_audio(use_speaker_detection?)`, `clear_transcription`,
`get_transcription` (read back `{text, truncated, status, has_transcription}`;
`truncated` flags when Resolve's preview cut the text off),
`perform_audio_classification`,
`analyze_for_intellisearch(identify_faces?, is_better_mode?)`, `analyze_for_slate(marker_color?)`,
`remove_motion_blur(deblur_option?)` (Resolve 21+; AI Extras / confirm-token gated as noted above),
`get_audio_mapping`, `get_mark_in_out`, `set_mark_in_out`

**`media_pool_item_markers`** — Markers and flags on clips in the Media Pool.
All actions require a `clip_id`.

Key actions: `add(frame, color, name, note, duration)`, `get_all`, `delete_by_color(color)`,
`delete_at_frame(frame)`, `add_flag(color)`, `get_flags`, `set_name(name)`

**`media_analysis`** — Project-scoped media intelligence and guarded metadata publishing.

Media Analysis and editorial-assist actions (v2.17.0+) add source-safe planning,
report reuse, persisted analysis execution, host_chat_paths visual review
(finalized per clip via `commit_vision`), transcription, default Resolve
metadata/marker writeback, and timeline-level editorial helpers.

Key actions: `capabilities`, `install_guidance`, `resolve_output_root`, `plan`,
`coverage_report`, `analyze_file`, `analyze_clip`, `analyze_bin`,
`analyze_project`, `detect_sync_events`, `add_sync_event_markers`,
`publish_clip_metadata`, `commit_vision`, `summarize`, `get_report`,
`build_index`, `index_status`, `query_index`, `start_batch_job`,
`run_batch_job_slice`, `batch_job_status`, `list_batch_jobs`,
`cancel_batch_job`, `resume_batch_job`, `review_timeline_markers`,
`cleanup_artifacts`, `db_status`, `db_ingest`, `get_panel_state`,
`set_panel_state`, `session_start_context`, `update_clip_field`,
`update_shot_field`, `get_field_history`, `revert_field`,
`list_corrections`, `deepen`, `commit_shot_vision`, `vision_pending_sweep`,
`build_embeddings`, `find_similar`, `detect_entities`, `commit_entities`,
`list_entities`, `prepare_bin_briefing`, `commit_bin_summary`,
`detect_shot_relationships`, `commit_shot_relationships`, and
`list_shot_relationships`.

**Cross-clip entities + bin briefing v2 (v2.44.0+).** Recurring
people/places/props across a project's media, found cheaply and confirmed
with ONE vision call per cluster:
- `detect_entities(threshold?, min_cluster_size?)` clusters the v10 CLIP
  frame vectors (build visual embeddings first), writes provisional entity
  rows + appearances, and returns a deferred payload with one
  representative frame per cluster (caps pre-checked, estimate inlined).
  The host chat reads those frames and calls
  `commit_entities(entities=[{entity_index, kind, label, description,
  confidence, merge_with?}], vision_token)` — conservative labels only
  (describe what's visible; never guess names). `merge_with` collapses
  clusters that show the same entity.
- `list_entities` returns labeled entities with per-clip/shot appearances;
  the panel's Review page shows a "Recurring across this bin" card.
- `prepare_bin_briefing` returns entities + per-clip summaries (text-only,
  no vision cost); the host writes a colleague-style markdown briefing and
  calls `commit_bin_summary(briefing, briefing_token)`, which lands in
  `memory/bin_summary.md` above the v2.0 aggregate.

**Cross-shot relationships (v2.49.0+).** Pattern recognition only (spec §4 —
no editorial suggestions): `same_setup_as` / `alt_take_of` (symmetric) and
`continues_from` (directional; the source shot continues from the target).
- `detect_shot_relationships(setup_threshold?, alt_take_threshold?,
  continues_band?, max_candidates?)` — pairwise cosine over the per-shot
  visual vectors (build visual embeddings first; raise
  `max_frames_per_clip` if shot coverage is partial), plus transcript
  continuity as a second signal for `continues_from`. Returns a deferred
  payload with a representative frame PAIR per candidate (caps pre-checked,
  two frames per candidate). Candidates live only in the detection-state
  stash until committed — re-detect replaces them.
- The host chat reads BOTH frames of each pair and calls
  `commit_shot_relationships(relationships=[{candidate_index, verdict:
  confirm|reject, relationship_type?, confidence?}], vision_token)`.
  Confirm only what the frames show; reject lookalikes. Overriding the
  suggested type is allowed. Committed rows supersede prior machine rows
  for the same pair.
- `list_shot_relationships(clip_id?, shot_uuid?, relationship_type?)` —
  current rows with clip/shot context on both ends. The shot page's
  Relationships group fills from these rows, and `plan_swap` prefers
  confirmed `alt_take_of` alternates over raw cosine (the rationale states
  which basis ranked each alternate).

**Embeddings + similarity (v2.43.0+).** Local-compute semantic search; no
vendor tokens, so nothing here touches the caps ledger. Backends are
detected, never installed (capabilities lists them with install guidance):
text = ollama serving `nomic-embed-text` or sentence-transformers; visual =
open_clip (ViT-B-32, needs torch); audio (v2.51.0+) = CLAP via
`transformers` (laion/clap-htsat-unfused, preferred) or the `laion_clap`
package — needs torch + ffmpeg.
- `build_embeddings(kinds=["text","visual","audio"]?, clip_id?)` —
  idempotent; embeds clip summaries, shot descriptions (+ deep field
  groups), transcript segments, and sampled frames (per-shot visual vector
  = mean of its frames'). `kinds=["audio"]` embeds one CLAP window per shot
  (center-cropped to ~10s, piped from the source media as raw PCM —
  read-only, no temp files) plus a clip-level mean vector; clips whose
  media is offline are reported in `skipped_missing_media`. Only re-embeds
  entities whose content changed.
- `find_similar(text=… | clip_id=… | clip_id+shot_index,
  kind="text"|"visual"|"audio", entity_types?, limit?)` — brute-force
  cosine over the project's vectors. Free-text visual queries use the CLIP
  text encoder ("cracked windshield" finds the frame); free-text audio
  queries use the CLAP text encoder ("engine revving" finds the shot).
  Results carry scores plus clip/shot/segment context.
The panel search box gains a `Semantic` toggle when a text backend is
detected. Vectors live in the per-project DB (schema v10).

**Deep shot-level vision tier (v2.42.0+).** Opt-in, estimate-first. Two
entry points share one per-shot schema (Visual / Content / Production /
Editorial / Cuttability / description / confidence):
- `depth="deep"` on any analyze action extends the deferred host-vision
  payload with `deep_shot_schema`; each `shot_descriptions` entry must carry
  the field groups. The first deep run returns `confirmation_required` with
  a token-cost estimate — re-call with `confirm_deep=true`. Caps still apply.
- `deepen(clip_id|clip_dir, shot_index?|shot_indices?)` runs the pass
  post-hoc on an already-analyzed clip. First call returns the estimate +
  `confirm_token`; re-call with the token to get the deferred payload, read
  its `frame_paths`, and commit via
  `commit_shot_vision(clip_id, shots=[{shot_index, ...groups...}],
  vision_token)`. Deep fields land as `vision_deep_v1` provenance rows;
  human corrections always survive. Shots with no sampled frames on disk get
  1–2 frames re-extracted via ffmpeg (read-only on source media).
`vision_pending_sweep(expire?, max_age_days?, reoffer?)` lists clips stuck
in `pending_host_analysis`; `reoffer=true` returns each clip's stored
deferred payload to finish the run, `expire=true` stamps them
`expired_host_analysis` so pendings never linger silently.

**DB-canonical analysis store (v2.41.0+).** The per-project SQLite DB
(`_soul/timeline_brain.sqlite`, schema v9+) is the source of truth for clip
analysis; `analysis.json` is a derived export written in lockstep. Analysis
runs write rows first (clips, shots, per-field subjective provenance,
transcript segments, sampled frames, QC observations) and then export the
JSON. Human corrections recorded via `update_clip_field` / `update_shot_field`
live as row-level provenance and always survive re-analysis. Readers
(panel API, exports) load DB-first and fall back to `analysis.json` for
reports that predate v9. `db_status` reports schema version + row counts;
`db_ingest` migrates an existing project's JSON reports (and
`corrections.json` sidecars) into the DB — run it once on older analysis
roots.
The tool never installs
dependencies and validates that outputs stay under
`davinci-resolve-mcp-analysis` project roots rather than beside source media.
Executed Resolve-target analysis defaults to running, persisting inspectable
artifacts, and publishing metadata plus Media Pool clip markers. Use
`dry_run=true`, `publish_metadata=false`, `timed_markers=no`, or
`session_only=true` with `keep_artifacts=false` to disable those defaults for a
run. Persisted analysis refreshes the local SQLite search index automatically unless
`auto_build_index=false` is set; `build_index` remains the manual rebuild action
for existing reports. `quick` uses ffprobe metadata; `standard` adds ffmpeg
read-through checks,
cut-boundary analysis from full-stream scene detection, flash-frame candidates,
motion/variance scoring, analysis keyframes, and sidecar reports.
`depth` controls which layers run; a separate `sampling_mode` controls how many
frames each clip gets for visual analysis (and thus token cost): `fixed`
(Economy, flat content-blind frames), `per_minute` (Balanced, frames scale with
duration), `adaptive_capped` (Thorough, content-aware bounded to
`[frame_floor, frame_ceiling]` — recommended/default), or `adaptive` (Thorough
uncapped). When no default is saved, the first analyze returns
`confirmation_required` with a `sampling_mode_prompt`; choosing a mode saves it
as the default. Pass `sampling_mode` per call for a one-off. The mode owns frame
count — `analysis_caps.frames_per_clip` is a safety ceiling above it, not the
primary dial.
By default, planning checks the active project's analysis root and bounded
related project-version roots for existing reports, then marks matching clips
`skip_execution=true` when those reports already contain the requested
technical, motion, transcription, and vision layers.
Resolve clip records also carry the published third-party
`davinci_resolve_mcp.analysis_report_path` when metadata writeback has run; use
that provenance as a first-class reuse hint even if the report lives under a
previous project-version analysis root.
The planner also maintains an `analysis_registry.json` under the analysis base
root. This registry indexes report paths by source path, clip id, media id, and
signature so project renames and versioned Resolve projects can still find prior
work quickly.
Reports include cache signatures with source stat, depth, frame budget, prompt
hash, and requested modalities. Use `force_refresh=true` for a fresh read,
`max_report_age_days` for freshness limits, and `reuse_policy="fresh"` when
unsigned older reports should not be reused. Pass `reuse_existing=false` only
when the user explicitly wants to ignore memory; pass
`search_related_project_roots=false` only for intentionally isolated runs.
If Resolve metadata shows prior MCP analysis but the planner cannot validate a
matching report, execution returns `status="reuse_blocked"` instead of silently
reanalyzing. Treat that as a project-memory integrity warning; restore the
report or pass `force_refresh=true` only when the user explicitly wants fresh
analysis.
Transcription, visual analysis, metadata writeback, and Media Pool marker
writeback are default-on. Vision uses
`vision.provider="host_chat_paths"`: analyze actions extract representative
frames to disk under the project analysis root and return a deferred payload
containing absolute `frame_paths`, a `shot_table` mapping each detected shot
range to its in-shot `frame_indices`, the JSON schema, and a `commit_action`.
The host chat must read those frames as local images, produce JSON per the
schema (including one `shot_descriptions` entry per `shot_index` in the
`shot_table`, grounded only in the frames listed for that shot), and call
`media_analysis(action="commit_vision", params={clip_id, visual,
vision_token})` per clip to merge the visual report, rebuild Media Pool clip
markers, and publish vision-dependent metadata to Resolve. Each Resolve shot
marker inherits its description from `shot_descriptions[shot_index]`; missing
entries fall back to an in-range `analysis_keyframe` and finally to a
clip-summary-tagged fallback — never to a neighbour shot's description. The manifest exposes
`vision_pending=True` and `pending_action` so callers know what is incomplete.
Pass `include_visuals=false`, `include_transcription=false`,
`publish_metadata=false`, or `timed_markers=no` to opt out. Agents must not add
those opt-out flags preemptively; use them only when requested or when a target
boundary requires it. Standard/deep runs prioritize first/last usable frames
plus before/after cut-boundary frames as the sampled set. Skipping
`commit_vision` leaves the run in `pending_host_vision_analysis` — that is a
failure mode to surface, not a silent downgrade. The local mock providers are
for tests and do not send frames off-machine.

When creating timelines through `media_pool`, use `if_exists="reuse"` for
idempotent reruns, `if_exists="version"` for deliberate alternate cuts, and
`if_exists="fail"` when duplicate names indicate a workflow error.
Use `detect_sync_events` before multicam setup, deliverable QC, or single-camera
sync review when the user needs likely 2-pop or slate-clap locations. It reads
source audio through FFmpeg/FFprobe only, returns advisory frames/timecodes and
per-file `record_offset` suggestions, and never installs FFmpeg automatically.
It also returns marker suggestions; `add_sync_event_markers` remains an explicit
marker-write action for standalone sync detections.
Use `publish_clip_metadata` when the user wants analysis to become searchable
inside Resolve. It analyzes or reuses reports, proposes field-specific merges
for `Description`, `Comments`, `Keywords`, `People`, and optional slate-derived
fields, stores provenance in third-party metadata, and writes metadata plus
source-time markers by default for executed Resolve-target analysis. Disable a
write run with `dry_run=true`, `publish_metadata=false`, or `timed_markers=no`.
`review_timeline_markers` creates a labeled
Resolve-rendered marker contact sheet plus JSON sidecar; with
`vision.enabled=true` it returns a host_chat_paths review payload (image_path +
prompt) so the host chat can read the sheet and answer inline — no commit step
required for marker review.

Before calling `analyze_*`, prefer `summarize` and `get_report` to discover
existing reports for the active project. If reports exist, use them as the
working memory for edit decisions and only request fresh analysis when a missing
layer changes the decision. If a user is
making story or audio-spine decisions and transcription is available but disabled,
tell them that transcript analysis may materially improve the edit instead of
silently skipping it. Resolve-native transcription changes project state; use it
only when that mutation is intentional.

---

### Timelines

**`edit_engine`** — Evidence-driven edit loops (v2.45.0+): selects assembly,
tighten, swap.

Every loop is plan → confirm → execute. plan_* actions are dry-run by
construction: they query the DB-canonical analysis store and return a
per-decision rationale plus a stored `plan_id` (plans persist under
`memory/edit_plans/` with a content fingerprint, so a stale 

…(truncated)
