DSH Plugins Marketplace

DSH Plugins

Plugins

/

lightroom-py

l

lightroom-py

Manifest valid

Adobe Lightroom Classic as native dsh tools through the lightroom-py MCP server: read the catalog, apply develop settings and presets, export JPEG/TIFF/PSD/DNG, and write ratings, labels, keywords and

hasBundlePatch

lightroom-py

Drive Adobe Lightroom Classic from Python and Claude. First open agent driver with verified programmatic mask creation (35.4% pixel-diff confirmed) and the AI mask compute path documented elsewhere as impossible.

Python 3.10+ License: MIT LR Classic 15.3 verified Tests

62 bridge handlers · 80 CLI verbs · 101 tests · 7+ real-LR validation sessions documented in CHANGELOG.md. Unofficial, MIT, not affiliated with Adobe.


Install — 3 user actions

pip install lightroom-py            # 1. install
lightroom setup                     # 2. one-command: plugin + LaunchAgent + skill
                                    # 3. In LR: Plug-in Manager → enable
                                    #    "lightroom-py bridge"  (~10 sec, one-time)

lightroom setup installs the LR plugin into ~/Library/Application Support/Adobe/Lightroom/Modules/, generates a bridge token at ~/.lightroom/profiles/default/bridge.json, registers a macOS LaunchAgent that auto-starts the bridge server on login (no terminal), and installs the Claude agent skill. The token auto-loads into LR's plugin — no manual paste.

Verify with lightroom doctor.

Install variants + macOS TCC gotcha + Windows notes

Variants

| Need | Command | |---|---| | Default (CLI + Python lib) | pip install lightroom-py | | With Claude Desktop MCP server | pip install "lightroom-py[mcp]" | | With ExifTool fast-path for XMP | pip install "lightroom-py[exiftool]" | | Everything (mcp + exiftool + dev) | pip install "lightroom-py[all]" |

macOS TCC-protected venvs

LaunchAgents on macOS can't read files under ~/Documents, ~/Desktop, ~/Downloads, ~/Pictures, ~/Movies, ~/Music without Full Disk Access. Install your venv outside those dirs:

python3 -m venv ~/.lightroom/venv
~/.lightroom/venv/bin/pip install lightroom-py
~/.lightroom/venv/bin/lightroom setup

lightroom setup and bridge install-service detect protected paths and refuse with workaround instructions before silently failing.

Windows

Manual bridge start (no LaunchAgent equivalent yet):

pip install lightroom-py
lightroom bridge install
lightroom bridge start         # leave running
# Then in LR: Plug-in Manager → enable

What you can do

| Surface | Verbs | |---|---| | Catalog | catalog open / info / stats — counts of photos / folders / keywords / collections | | Photos | photos list / count / find-by-path — filter by rating, camera, lens, keyword, date, color label, file format, ISO, aperture, focal length, GPS; SQLite read fast-path (50k+ catalogs return instantly) | | Selection + nav | select, select-all/none/inverse/extend, next, previous | | Flags + ratings | flag-pick/reject/clear, rate-up/rate-down, color-cycle | | Metadata | add-keywords (hierarchical "People\|Family\|Mom"), rate, color, set-iptc (caption/title/headline/copyright/creator/city/state/country) | | XMP | metadata write-xmp / read-xmp + ExifTool fast-path | | Develop — globals | apply-preset, apply-settings, paste-settings --subset, get-settings, copy, reset, live set | | Develop — typed | crop, hsl, color-grade, transform, lens-correction, calibration, detail, effects | | Develop — tone curve | curve get/set/preset/linear/s-curve — RGB + per-channel | | Develop — snapshots | snapshot create/list — safety checkpoints before agent edits | | Develop — process version | process-version get/set | | Develop — targeted resets | reset-crop / -masking / -spot / -redeye / -transforms | | Masks — read + clear | mask list / clear (unified MaskGroupBasedCorrections schema, LR 15.3+) | | Masks — create ⭐ | mask create-radial (verified end-to-end) + create-linear (best-effort) with 20+ Local* adjustments per mask | | AI mask compute ⭐ | apply-preset --folder "Adaptive: Subject" + library export → LR's "AI Updates Required" dialog → one click → mask renders (verified 20.91% pixel-diff) | | Collections | list / create / add / remove / delete / get-photos — regular + smart | | Library | list-folders, export (JPEG/TIFF/PSD/DNG with watermark, output sharpening, resize, DPI, filename templates, minimize-metadata), make-virtual-copy, stack | | Edit-In | export to disk, run for full roundtrip (export → external tool → reimport as stack) | | Dev tools | bridge reload (hot-reload Lua handlers without LR restart), bridge eval (arbitrary Lua), bridge tail-log | | Service mgmt (macOS) | bridge install-service / uninstall-service / service-status |

What's NOT implementable (Adobe SDK gaps, documented)

| Surface | Why | |---|---| | AI Denoise compute | LR exposes no public trigger for Enhance → Denoise…. Stage settings, user clicks Enhance. | | Brush mask creation | Mask/Paint schema (Dabs: stroke array) not yet probed. Use radial as workaround for v0.6. | | Spot removal create | Not exposed in LR 15.3. | | Photo deletion | cat:trashPhotos doesn't exist in 15.3. | | Virtual copy delete | Only creation works. | | Lightroom Cloud (LR CC) | Partner-API gated; we target LR Classic. |


Command cheatsheet

Full reference: docs/cli-reference.md. The 20 most common patterns:

# === Setup + health ===
lightroom setup                                              # one-shot: plugin + service + skill
lightroom doctor                                             # diagnose install + bridge state
lightroom bridge ping                                        # round-trip test

# === Catalog + cull ===
lightroom catalog open ~/Pictures/Lightroom/MyCatalog.lrcat
lightroom photos list --rating ">=4" --iso ">=400" --since 2026-01-01 --json
lightroom photos count --keyword wedding
lightroom photos select-all
lightroom photos flag-pick --selection
lightroom photos rate-up --selection                         # cycle +1 star

# === Metadata ===
lightroom metadata add-keywords "wedding,bride,People|Family|Mom" --selection
lightroom metadata rate 5 --selection
lightroom metadata set-iptc -f caption="Sunset" -f city="Paris" --selection

# === Global develop ===
lightroom develop list-presets
lightroom develop apply-preset "Pop" --folder "Adaptive: Subject" --selection
lightroom develop apply-settings '{"Exposure2012":0.5,"Contrast2012":20}' --selection
lightroom develop hsl --saturation orange=10 --luminance blue=15 --selection
lightroom develop color-grade --shadow-hue 215 --shadow-sat 20 \
                              --highlight-hue 30 --highlight-sat 25 --selection
lightroom develop curve preset "Medium Contrast" --selection

# === ⭐ Geometry mask creation (v0.6, verified) ===
lightroom develop mask create-radial --left 0.05 --right 0.5 \
    --top 0.4 --bottom 0.95 --exposure 1.0 \
    --name "subject-brighten" --selection
lightroom develop mask create-radial --top 0.15 --bottom 0.85 \
    --left 0.15 --right 0.85 --invert --exposure -1.0 --feather 70 --selection
    # ↑ vignette-style darkening (invert = effect OUTSIDE the ellipse)

# === Safety + experimentation ===
lightroom develop snapshot create "Pre-agent-edit" --selection
lightroom develop mask list --selection                      # see what masks are on the photo
lightroom develop mask clear --kind all --selection          # wipe all masks
lightroom develop reset --selection                          # full reset

# === Production export ===
lightroom library export ~/Desktop/finals --selection --format JPEG \
    --quality 88 --resize-long-edge 1920 --sharpening standard --dpi 96

# === External tool roundtrip ===
lightroom edit-in run "magick {input} -auto-level {output}" --selection

Three ways to use

1. CLI

lightroom photos list --rating ">=4" --iso ">=400" --json
lightroom develop apply-preset "Pop" --folder "Adaptive: Subject" --selection
lightroom develop mask create-radial --left 0.05 --right 0.5 --top 0.4 --bottom 0.95 \
    --exposure 1.0 --selection                          # ⭐ verified renders
lightroom library export ~/finals --selection --format JPEG \
    --resize-long-edge 1920 --sharpening standard --dpi 96

2. Python API

import asyncio
from lightroom import LightroomClient

async def main():
    async with LightroomClient.connect() as lr:
        await lr.catalog.open("~/Pictures/Lightroom/MyCatalog.lrcat")
        keepers = await lr.photos.list(rating_gte=4, iso_gte=400, since="2026-01-01")
        for p in keepers:
            await lr.develop.apply_preset("Pop", folder="Adaptive: Subject", photo_uuids=[p.uuid])
            await lr.develop.mask_create_radial(
                left=0.05, right=0.5, top=0.4, bottom=0.95,
                exposure=1.0, photo_uuids=[p.uuid],
            )

asyncio.run(main())

Full async sub-client reference: docs/python-api.md.

3. Claude / agent skill

The package ships a canonical SKILL.md installable via lightroom skill install (also done automatically by lightroom setup). It activates on /lightroom or intent like "cull these photos", "apply my warm preset to the selection", "export the 5-star photos as JPEGs".

For Claude Desktop's MCP integration: pip install "lightroom-py[mcp]" + point Claude Desktop's config at the bundled lightroom-mcp binary. See docs/mcp.md.

4. DeepSeek Harness (dsh)

This repository is also a DeepSeek Harness plugin bundle (package.json + cordis.patch.yml at the root — pure configuration, no build step):

pip install "lightroom-py[mcp]"                        # the MCP server (0.6.1+; on 0.6.0 add "mcp<2")
dsh plugin add github:drshy-org/lightroom-py           # the bundle; tools appear as mcp__lightroom_py__*

All 15 MCP tools become native dsh tools; the agent skill is shipped as dsh/skills/lightroom/SKILL.md. Details and the skill-discovery note: dsh/README.md. Any other MCP client (Codex CLI, Cursor, Gemini CLI, OpenCode) works the same way — point it at the lightroom-mcp binary.


Why this exists

LR Classic is the most locked-down RAW editor for automation: no AppleScript, no COM, no UXP. The Lua plugin SDK is the only door, and LrSocket / LrHttp are outbound-only — a plugin physically cannot host a server. lightroom-py is the missing Python-side counterpart: a tiny .lrplugin polls a local Python HTTP server, and Python (or Claude via the bundled agent skill / MCP server) drives Lightroom by enqueueing commands.

Claude Desktop / Code / CLI ──HTTP──▶  lightroom-py (Python aiohttp)
                                              ▲
                                              │ poll / respond
                                              │
                              .lrplugin ──────┘  (Lua, runs inside LR)

Configuration

| Variable | Default | Purpose | |---|---|---| | LIGHTROOM_HOME | ~/.lightroom | Config root | | LIGHTROOM_PROFILE | default | Per-agent isolation |

The bridge server reads host / port / token from $LIGHTROOM_HOME/profiles/$LIGHTROOM_PROFILE/bridge.json — auto-generated on first lightroom setup. bridge.json is the single source of truth; the LR plugin reads it directly.


Troubleshooting

| Symptom | Fix | |---|---| | doctor says "Bridge plugin not installed" | lightroom setup | | doctor says "loaded but not currently running" + last_exit=256 | macOS TCC blocked the venv. Reinstall outside ~/Documents/. | | bridge ping times out | lightroom bridge install --force && lightroom bridge reload. For Lua changes outside Handlers.lua: Cmd+Q LR + relaunch. | | Plugin disabled after a Lua error | LR auto-disables on plugin init crash. File → Plug-in Manager → re-enable. | | Yielding is not allowed within a C or metamethod call | Use LrTasks.pcall instead of bare pcall. See CHANGELOG v0.1.2 / v0.3.1 / v0.4.1. | | AI mask preset applied but export looks unchanged | Click Export on the "AI Updates Required" modal with the "Update affected photos" box checked. |

For the developer log: lightroom bridge tail-log -n 50.


Development

git clone https://github.com/drshy-org/lightroom-py.git
cd lightroom-py
python -m venv .venv && source .venv/bin/activate
pip install -e ".[all]"
pre-commit install
ruff format . && ruff check . && mypy && pytest

See CONTRIBUTING.md for the ranked backlog, architecture details, the LR sandbox gotchas list, and the hot-reload dev loop.


Roadmap

| Version | Status | |---|---| | v0.1–v0.3 | Scaffold, bridge protocol, SQLite read, metadata writes, Collections/Library/Edit-In, MCP server, hot-reload tooling | | v0.4 | Feature catch-up: tone curve, snapshots, process version, paste-settings, mask read/clear, AI staging | | v0.4.2 | Install simplification — setup, LaunchAgent, token auto-load, TCC defensive check | | v0.5 | Typed Develop wrappers, EXIF query layer, production exports | | v0.6 (current) | Geometry mask CREATION (radial verified). Unified MaskGroupBasedCorrections mask_list rewrite. | | v0.7 | Brush mask schema probe + create, linear mask empirical verification, Windows LaunchAgent, .mcpb Claude Desktop bundle | | Out of scope | LR Cloud, AppleScript (LR doesn't expose), photo deletion + virtual-copy delete + AI compute trigger (SDK gaps) |


Contact

Built by drshydrshy.xyz. Issues + PRs at github.com/drshy-org/lightroom-py. If lightroom-py saves you time, a star ⭐ is appreciated.

Citation

If you use lightroom-py in research, blog posts, papers, or talks, please cite it. GitHub auto-detects CITATION.cff and shows a "Cite this repository" button on the right sidebar.

Plain-text / APA:

drshy. (2026). lightroom-py: A Python and Claude agent driver for Adobe Lightroom Classic (v0.6.0) [Software]. Retrieved from https://github.com/drshy-org/lightroom-py — http://www.drshy.xyz

BibTeX:

@software{drshy_lightroom_py_2026,
  author       = {drshy},
  title        = {{lightroom-py}: {A} {Python} and {Claude} agent driver for {Adobe} {Lightroom} {Classic}},
  url          = {https://github.com/drshy-org/lightroom-py},
  version      = {0.6.0},
  date         = {2026-05-10},
  note         = {Author homepage: \url{http://www.drshy.xyz}}
}

If your work uses one of the specific empirical results from this project (the verified geometry mask creation pixel-diff, the AI mask compute path, the LR Classic 15.3 sandbox gotchas catalog), please link to the relevant CHANGELOG.md version entry so readers can find the original evidence.

License

MIT — see LICENSE. Use freely; no warranty; not affiliated with Adobe.

Similar plugins

dsh-pouch

A pouch of practical micro-plugins for DSH: per-turn wall-clock time injection, safe restart, session ID header badge, Tavily search provider, configurable LLM request-header routes, and an MCP server

Tools & CapabilitiesManifest valid

0

dsh plugin --profile web add @moon16u/dsh-pouch

MCP marketplace and management panel in the Web sidebar: one-click official templates (Apifox public/private, Apipost, MasterGo, Pixso), paste raw mcpServers JSON, and enable, edit or delete your serv

Tools & CapabilitiesManifest valid

0

286/wk

dsh plugin --profile web add dsh-mcp-market

Official DSH plugin for nuphus-mcp (by the nuphus-mcp maintainers): desktop and browser automation (38 tools) with PaddleOCR element perception and Chrome CDP browsing, via a persistent stdio MCP chil

Tools & CapabilitiesManifest valid

0

77/wk

dsh plugin --profile web add dsh-nuphus-mcp

Pi-compatible tool suite recreated inside DeepSeek Harness: installs lower-case read/write/edit/bash/find/grep/ls core tools while retaining DSH-backed web, task, plan, todo, think, and slash extensio

Tools & CapabilitiesManifest valid

0

dsh plugin --profile web add dsh-pi-compatible

Bridges a local MATLAB MCP server into DSH: evaluate MATLAB code, run .m scripts and tests, and inspect installed toolboxes via mcp__matlab__* tools.

Tools & CapabilitiesManifest valid

0

dsh plugin --profile web add dsh-mcp-matlab

Real-browser automation for dsh via an MCP server (Playwright core): navigate, click, fill, type, screenshot, and act on accessibility snapshots with numbered references - all 22 web_* tools re-expose

Tools & CapabilitiesManifest valid

0

30/wk

dsh plugin --profile web add web-bridge-mcp