The missing CLI and Python library for DaVinci Resolve. Declarative, scriptable, LLM-friendly.
Project description
dvr
The missing CLI and Python library for DaVinci Resolve.
Declarative. Scriptable. LLM-friendly. No more silent None returns.
pip install dvr
$ dvr timeline inspect
{
"name": "Edit_v2",
"fps": 24.0,
"duration_frames": 86400,
"tracks": {
"video": [{"index": 1, "name": "V1", "clips": 1, "enabled": true}, ...],
"audio": [{"index": 1, "name": "A1", "clips": 4, "subtype": "stereo"}, ...]
},
"markers": [...],
"color": {"science": "DaVinci YRGB Color Managed v2", "input": "Rec.2020", ...}
}
Why this exists
DaVinci Resolve has a powerful Python scripting API. It's also painful:
- Silent failures everywhere.
AddRenderJob()returnsNoneon success or failure — good luck. - String-keyed settings with undocumented valid values.
- No batch operators. You loop everything.
- macOS connection footguns. Resolve binds to LAN IP; vanilla
scriptapp('Resolve')returnsNone. - Chain navigation. Every
.Get*()can returnNone. One typo and you're traversing nothing. - 20+ export formats behind magic enum constants.
dvr wraps the API with a clean object model, idempotent operations, decoded errors, structured I/O, and a CLI that's pleasant for humans and parseable by LLM agents.
Three ways to use it
1. Python library
from dvr import Resolve
r = Resolve() # auto-connects, handles macOS LAN-IP quirk
with r.project.use("MyShow"):
tl = r.timeline.current
print(tl.inspect()) # one call, full state
# Query language operates on inspected state
bad = tl.clips.where(lambda c: c.duration < 12)
for clip in bad:
clip.add_marker(color="red", note="too short")
job = r.render.submit(preset="delivery")
job.wait() # blocks with progress
print(job.output_path)
2. CLI
$ dvr project ensure MyShow --color rec2020_pq_4000 --fps 24
$ dvr timeline inspect | jq '.tracks.video[].clips'
$ dvr render submit --preset delivery --wait --stream
{"job_id": "abc", "status": "rendering", "pct": 12, "eta_s": 240}
{"job_id": "abc", "status": "rendering", "pct": 24, "eta_s": 210}
{"job_id": "abc", "status": "complete", "output": "/path/out.mov"}
3. MCP server (for LLM agents)
$ pip install dvr
$ dvr mcp install-claude # one-shot Claude Desktop setup
$ dvr mcp serve # or run the server yourself
$ dvr mcp tools # introspect the 39+ typed tools
LLM agents call typed tools directly — no shell parsing, no silent failures. Tools that don't need a live Resolve (version, doctor, static schema topics) work even when Resolve isn't running, so first-time setup is instant. See docs/mcp.md.
Five things that make it fundamentally better than the raw API
- One
inspect()call replaces ten API calls. Full structured state in a single round-trip. - Idempotent operations.
project.ensure(),timeline.ensure(),bin.ensure()— re-run anything safely. - Decoded errors. Every failure carries
cause,fix, andstate. No moreNone. - Declarative specs.
dvr apply project.dvr.yamlreconciles state.kubectl applyfor DaVinci. - Persistent connection.
dvr servekeeps Resolve warm — sequential commands run in <100ms.
Install
| Channel | Command |
|---|---|
| Homebrew (macOS / Linux) | brew install mhadifilms/tap/dvr |
| PyPI | pip install dvr |
| pipx | pipx install dvr |
| uv | uv tool install dvr |
| From source | git clone https://github.com/mhadifilms/dvr && cd dvr && pip install -e ".[dev]" |
Optional extras
pip install "dvr[docs]" # docs site dependencies
pip install "dvr[dev]" # dev (ruff, mypy, pytest)
MCP support is included in the default install.
Homebrew details
dvr ships via my personal tap at mhadifilms/homebrew-tap. The recommended pattern is to tap once, then use the bare command:
brew tap mhadifilms/tap
brew install dvr # works after the tap is installed
Or, if you only ever want to install once and don't care about updates:
brew install mhadifilms/tap/dvr
brew install dvrsays "no formula"? That's expected if you haven't tapped yet. Homebrew only searcheshomebrew/coreby default; our formula lives in our personal tap. Runbrew tap mhadifilms/tapand try again.
Requirements
- Python 3.10+ (matches Resolve's embedded Python on current versions)
- DaVinci Resolve Studio 18.5+ — external scripting is a Studio-only feature. Blackmagic Design sells Studio as a one-time $295 perpetual license or via Blackmagic Cloud at $30/month per seat.
- macOS, Windows, or Linux
dvr auto-discovers Resolve's scripting library on each platform. No environment variables needed for typical installs.
The free edition of DaVinci Resolve cannot be scripted from outside the app (Blackmagic restricted this in v19.1+). If you're evaluating
dvrwithout Studio, use--dry-runflags onapplyand explore the schema/inspection commands — they work without a live connection.
Status
Stable from 1.0. Breaking changes ship with a deprecation cycle and a major version bump; new features land as minor releases. See CHANGELOG.md.
License
MIT — see LICENSE.
Contributing
Issues and pull requests welcome. The project's API surface is large; contributions covering edge cases on Windows / Linux are especially valuable. See CONTRIBUTING.md for setup and conventions.
dvris an independent open-source project. It is not affiliated with, endorsed by, or sponsored by Blackmagic Design. "DaVinci" and "DaVinci Resolve" are trademarks of Blackmagic Design Pty Ltd.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dvr-1.1.4.tar.gz.
File metadata
- Download URL: dvr-1.1.4.tar.gz
- Upload date:
- Size: 321.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f4b0d9db3051e97c01e2814591e2cfc5a8959bb8416aaf935ff3b9cc093ad0df
|
|
| MD5 |
c59cfd5f853caf0a76b32e42113e0463
|
|
| BLAKE2b-256 |
c4c98d996f352f2a9862c8092163e64317cfc67cae63fcbc7b133ff66d02a264
|
Provenance
The following attestation bundles were made for dvr-1.1.4.tar.gz:
Publisher:
release.yml on mhadifilms/dvr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dvr-1.1.4.tar.gz -
Subject digest:
f4b0d9db3051e97c01e2814591e2cfc5a8959bb8416aaf935ff3b9cc093ad0df - Sigstore transparency entry: 1409218290
- Sigstore integration time:
-
Permalink:
mhadifilms/dvr@6b3de219d51fa32f779542df4e7325d1999906a2 -
Branch / Tag:
refs/tags/v1.1.4 - Owner: https://github.com/mhadifilms
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6b3de219d51fa32f779542df4e7325d1999906a2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dvr-1.1.4-py3-none-any.whl.
File metadata
- Download URL: dvr-1.1.4-py3-none-any.whl
- Upload date:
- Size: 306.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4a223d0d027ff6393ca7951dc3ba7b5c999536884719094d5a17f7ce6304fa0
|
|
| MD5 |
4327a0767e1e17f4bb35790a1be2d7be
|
|
| BLAKE2b-256 |
b9652714a26040076b3c5515f37c4ed53edaa70329e1100d2d344c888a620dca
|
Provenance
The following attestation bundles were made for dvr-1.1.4-py3-none-any.whl:
Publisher:
release.yml on mhadifilms/dvr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dvr-1.1.4-py3-none-any.whl -
Subject digest:
c4a223d0d027ff6393ca7951dc3ba7b5c999536884719094d5a17f7ce6304fa0 - Sigstore transparency entry: 1409218305
- Sigstore integration time:
-
Permalink:
mhadifilms/dvr@6b3de219d51fa32f779542df4e7325d1999906a2 -
Branch / Tag:
refs/tags/v1.1.4 - Owner: https://github.com/mhadifilms
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6b3de219d51fa32f779542df4e7325d1999906a2 -
Trigger Event:
push
-
Statement type: