| name | resolve-color |
| description | 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. |
Resolve Color / Grade — Claude Code Skill
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.