Resolve Color / Grade
Bridges color craft to this repo's tools. This skill does not duplicate the
manuals — it tells you which one to open and the rules that cross both servers.
- Craft / taste —
docs/guides/color-decision-guide.md (project-owned color
guidance and API boundaries). The global colorist / colorist-assistant
skills add colorist philosophy; use them for how to see, not tool mechanics.
- Live tool mechanics —
docs/kernels/color-grade-kernel.md (the
timeline_item_color boundary layer).
- Offline grade compute —
resolve-advanced/README.md → the drx grading/QC
catalog (the "Advanced (offline) server" section of the color kernel).
Two servers, one grade
| Job |
Server |
Tools |
| Drive a running Resolve |
davinci-resolve (Python, live) |
timeline_item_color, graph, gallery_stills, color_group |
Compute a grade offline from frames, or read/write .drx/.drp grades with no Resolve open |
davinci-resolve-advanced (Node) |
drx, drp, project_db, provenance |
Division of labor: the advanced server computes a grade and writes an
apply-ready .drx; applying it is the live server's job
(timeline_item_color.safe_apply_drx). Node never drives Resolve.
What this build cannot do (check before you offer it)
The scripting API changes per patch release, so "Resolve 21" is not a usable
label. Read resolve_control get_version → build.unavailable_on_this_build
before offering a gated surface; check_version_support asks about one named
symbol. Gated in this domain:
| Surface |
Needs |
If absent |
TimelineItem.ResetAllNodeColors |
20.2 |
Clear node colors one at a time via the graph node-color setter, or leave them |
An empty unavailable_on_this_build means nothing recorded is missing, not
that everything exists — most of the API has never been version-bisected. A
symbol with no gate returns unknown, which means probe it. Probe with
name in dir(obj), never bare hasattr: on a Resolve object hasattr returns
True for every name, real or invented, so it can only say yes.
The offline drx / project_db routes are not version-gated this way —
they read and write files, so they work regardless of the build attached, and
are the fallback when a live surface turns out to be missing.
The frame-first rule (non-negotiable — see AGENTS.md)
Before applying any grade, look, shot match, LUT, CDL, DRX, or copied grade to a
real timeline, inspect representative Resolve-rendered frames (thumbnails,
contact sheets, Gallery stills, marker frames, or a scratch-only visual report).
Compare bypass/current/after at matched timecodes when the API allows, and
restore the prior version/node state after any temporary bypass. Never grade
from metadata, graph availability, or a style label alone unless the user
explicitly asks for a blind/global pass. Preserve a recoverable grade version and
report which frames informed the change. Frames extracted for offline compute go
to scratch/analysis locations only — never touch source media (AGENTS.md).
Offline grading / QC catalog (drx actions)
Frame-stats → arithmetic → .drx. All local, deterministic, guarded (they
refuse to fabricate a match rather than emit a silent no-op). Extraction and
apply are the caller's job. Pick by intent:
- Match toward a reference still —
match_to_reference (affine mean/std,
skin-line gated, luma-preserving).
- Within-camera drift —
level_clips (exposure/WB to a group hero).
- Cross-camera skin cohesion —
skin_match (skin-gated; throws on
log/wrong-space frames).
- B-roll cohesion —
shot_match (gray-world neutralize or hero match).
- Known-neutral patch / gray card —
white_balance_match.
- Black/white points to a hero —
contrast_normalize.
- Saturation cohesion —
saturation_match. Shadow cast — black_balance.
- Import ASC CDL (
.cc/.ccc/.cdl) — cdl_io. Copy a Body look —
grade_transfer. Attach a .cube LUT to a node — lut_apply.
- Season/host look —
author_look / carry_look.
- Read frames —
scope_read (parade/vectorscope/black-balance/clip%),
intent_tags (low_key / motivated_warm, to exclude from neutralize),
gamut_legal (broadcast-legal, measurement only).
- Verify —
verify_grade (intended vs applied → landed/drifted/missing).
Did the grade damage the image? (media_analysis assess_grade)
verify_grade asks did Resolve apply what I asked. This asks is the result
any good — a grade can land perfectly and still be flat, milky, crunchy or
banded.
media_analysis(action='assess_grade', params={
source_path, graded_path | lut_path, time_seconds, working_space })
Deterministic numpy on a decoded frame of the real result (a rendered file,
or the source pushed through the LUT by ffmpeg) — never a simulated transform,
because LUT interpolation and encode rounding are where banding is introduced.
Returns acceptable, flags (each with a remedy), the raw measurements, and a
grade_shift_delta_e2000 magnitude.
- Flags:
flat, milky, washed_out, noisy, clipped, posterized,
banding. Read them and reject your own grade rather than shipping the
first look that rendered.
- Display-referred only. ACEScct / S-Log3 / LogC are refused, not
converted — the right transform depends on camera and project colour
management, which a frame cannot tell you. Convert first, then re-run.
vision in the result says whether a paid second opinion is warranted.
Content-dependent flags (banding on a real sky gradient, a deliberate
washed_out) escalate; unambiguous damage does not. A clean grade costs zero
tokens.
Cross-server gotchas that bite
- Grade value space.
drx generate/merge default to space:'ui'
(Resolve PANEL units; saturation 0–100, neutral 50). Pass space:'drx' only
for raw internal floats. Decoded values are ground truth only for the
calibrated set — check the valueFidelity marker
(resolve-advanced/vendor/drx-parameters/CALIBRATION-STATUS.md).
- Hue-axis curves. Naive
[0,1] point lists are auto-canonicalized into the
verified bezier cage. If a result carries a warnings array, the curve went
through raw and will render FLAT — surface it, do not ship silently.
- Apply targeting.
safe_apply_drx defaults to video track 1 / item 0 —
always pass track_type/track_index/item_index explicitly, and grab a
still/.drx backup first (it does not snapshot). ApplyGradeFromDRX replaces
the graph — no append mode.
- Relayout ("Cleanup Node Graph," no UI API). Single clip, live: grab still →
drx(action="relayout") → graph.reset_all_grades → safe_apply_drx with
explicit indices (a same-structure apply keeps the OLD layout — the reset is
required). Whole project, offline: project_db(action="relayout_node_graphs").
- Guards are load-bearing. A thrown "refused" error usually means wrong input
space, log-encoded frames, or missing media — read it before retrying. The
grading catalog needs
sharp; call the advanced capabilities tool for live
status + install hints.
1---2name: resolve-color3description: Color grading and look work in the DaVinci Resolve MCP. Apply when grading, correcting, matching shots, developing looks, or applying/modifying LUTs, CDLs, DRX grades, or copied grades — live in a running Resolve OR offline against .drx/.drp files. Routes to the live Python color tools, the offline advanced grading/QC catalog, and the project's color craft guidance.4---56# Resolve Color / Grade7Bridges color *craft* to this repo's *tools*. This skill does not duplicate the8manuals — it tells you which one to open and the rules that cross both servers.910- **Craft / taste** — `docs/guides/color-decision-guide.md` (project-owned color11 guidance and API boundaries). The global `colorist` / `colorist-assistant`12 skills add colorist philosophy; use them for *how to see*, not tool mechanics.13- **Live tool mechanics** — `docs/kernels/color-grade-kernel.md` (the14 `timeline_item_color` boundary layer).15- **Offline grade compute** — `resolve-advanced/README.md` → the `drx` grading/QC16 catalog (the "Advanced (offline) server" section of the color kernel).1718## Two servers, one grade1920| Job | Server | Tools |21|---|---|---|22| Drive a **running** Resolve | `davinci-resolve` (Python, live) | `timeline_item_color`, `graph`, `gallery_stills`, `color_group` |23| Compute a grade **offline** from frames, or read/write `.drx`/`.drp` grades with **no Resolve open** | `davinci-resolve-advanced` (Node) | `drx`, `drp`, `project_db`, `provenance` |2425**Division of labor:** the advanced server *computes* a grade and writes an26apply-ready `.drx`; **applying** it is the live server's job27(`timeline_item_color.safe_apply_drx`). Node never drives Resolve.2829## What this build cannot do (check before you offer it)3031The scripting API changes per **patch** release, so "Resolve 21" is not a usable32label. Read `resolve_control get_version` → `build.unavailable_on_this_build`33before offering a gated surface; `check_version_support` asks about one named34symbol. Gated in *this* domain:3536| Surface | Needs | If absent |37|---|---|---|38| `TimelineItem.ResetAllNodeColors` | 20.2 | Clear node colors one at a time via the `graph` node-color setter, or leave them |3940An empty `unavailable_on_this_build` means **nothing recorded is missing**, not41that everything exists — most of the API has never been version-bisected. A42symbol with no gate returns `unknown`, which means probe it. Probe with43`name in dir(obj)`, never bare `hasattr`: on a Resolve object `hasattr` returns44`True` for every name, real or invented, so it can only say yes.4546The offline `drx` / `project_db` routes are **not** version-gated this way —47they read and write files, so they work regardless of the build attached, and48are the fallback when a live surface turns out to be missing.4950## The frame-first rule (non-negotiable — see AGENTS.md)5152Before applying any grade, look, shot match, LUT, CDL, DRX, or copied grade to a53real timeline, **inspect representative Resolve-rendered frames** (thumbnails,54contact sheets, Gallery stills, marker frames, or a scratch-only visual report).55Compare bypass/current/after at matched timecodes when the API allows, and56restore the prior version/node state after any temporary bypass. Never grade57from metadata, graph availability, or a style label alone unless the user58explicitly asks for a blind/global pass. Preserve a recoverable grade version and59report which frames informed the change. Frames extracted for offline compute go60to scratch/analysis locations only — **never touch source media** (AGENTS.md).6162## Offline grading / QC catalog (`drx` actions)6364Frame-stats → arithmetic → `.drx`. All local, deterministic, guarded (they65**refuse** to fabricate a match rather than emit a silent no-op). Extraction and66apply are the caller's job. Pick by intent:6768- **Match toward a reference still** — `match_to_reference` (affine mean/std,69 skin-line gated, luma-preserving).70- **Within-camera drift** — `level_clips` (exposure/WB to a group hero).71- **Cross-camera skin cohesion** — `skin_match` (skin-gated; throws on72 log/wrong-space frames).73- **B-roll cohesion** — `shot_match` (gray-world neutralize or hero match).74- **Known-neutral patch / gray card** — `white_balance_match`.75- **Black/white points to a hero** — `contrast_normalize`.76- **Saturation cohesion** — `saturation_match`. **Shadow cast** — `black_balance`.77- **Import ASC CDL** (`.cc`/`.ccc`/`.cdl`) — `cdl_io`. **Copy a Body look** —78 `grade_transfer`. **Attach a `.cube` LUT to a node** — `lut_apply`.79- **Season/host look** — `author_look` / `carry_look`.80- **Read frames** — `scope_read` (parade/vectorscope/black-balance/clip%),81 `intent_tags` (low_key / motivated_warm, to exclude from neutralize),82 `gamut_legal` (broadcast-legal, measurement only).83- **Verify** — `verify_grade` (intended vs applied → landed/drifted/missing).8485## Did the grade damage the image? (`media_analysis assess_grade`)8687`verify_grade` asks *did Resolve apply what I asked*. This asks *is the result88any good* — a grade can land perfectly and still be flat, milky, crunchy or89banded.9091 media_analysis(action='assess_grade', params={92 source_path, graded_path | lut_path, time_seconds, working_space })9394Deterministic numpy on a decoded frame of the **real** result (a rendered file,95or the source pushed through the LUT by ffmpeg) — never a simulated transform,96because LUT interpolation and encode rounding are where banding is introduced.97Returns `acceptable`, `flags` (each with a remedy), the raw measurements, and a98`grade_shift_delta_e2000` magnitude.99100- Flags: `flat`, `milky`, `washed_out`, `noisy`, `clipped`, `posterized`,101 `banding`. **Read them and reject your own grade** rather than shipping the102 first look that rendered.103- **Display-referred only.** ACEScct / S-Log3 / LogC are *refused*, not104 converted — the right transform depends on camera and project colour105 management, which a frame cannot tell you. Convert first, then re-run.106- `vision` in the result says whether a paid second opinion is warranted.107 Content-dependent flags (`banding` on a real sky gradient, a deliberate108 `washed_out`) escalate; unambiguous damage does not. A clean grade costs zero109 tokens.110111## Cross-server gotchas that bite112113- **Grade value space.** `drx` `generate`/`merge` default to `space:'ui'`114 (Resolve PANEL units; saturation 0–100, neutral 50). Pass `space:'drx'` only115 for raw internal floats. Decoded values are ground truth only for the116 calibrated set — check the `valueFidelity` marker117 (`resolve-advanced/vendor/drx-parameters/CALIBRATION-STATUS.md`).118- **Hue-axis curves.** Naive `[0,1]` point lists are auto-canonicalized into the119 verified bezier cage. If a result carries a `warnings` array, the curve went120 through raw and will render **FLAT** — surface it, do not ship silently.121- **Apply targeting.** `safe_apply_drx` defaults to video track 1 / item 0 —122 **always pass `track_type`/`track_index`/`item_index` explicitly**, and grab a123 still/`.drx` backup first (it does not snapshot). `ApplyGradeFromDRX` *replaces*124 the graph — no append mode.125- **Relayout ("Cleanup Node Graph," no UI API).** Single clip, live: grab still →126 `drx(action="relayout")` → `graph.reset_all_grades` → `safe_apply_drx` with127 explicit indices (a same-structure apply keeps the OLD layout — the reset is128 required). Whole project, offline: `project_db(action="relayout_node_graphs")`.129- **Guards are load-bearing.** A thrown "refused" error usually means wrong input130 space, log-encoded frames, or missing media — read it before retrying. The131 grading catalog needs `sharp`; call the advanced `capabilities` tool for live132 status + install hints.