lightcraft
Skill36 starsChanged 9 days agoMITView on GitHub
Photo development and cataloguing with LightCraft (Lightroom-style): import and cull a shoot, rate / flag / keyword, develop RAW (DNG, CR2, CR3, NEF, ARW, RAF…) and JPEG photos (exposure, white balance, tone curve, HSL, B&W, crop, masks), HDR editing, apply presets, sync edits across a batch, HDR / panorama merge, slideshows (AV1 video / PDF), print layouts, print templates and contact sheet PDFs, batch export JPEG / PNG / TIFF / WebP / AVIF / JPEG XL / PSD / DNG.
1 other project uses a version of this.
Adopted by
Most recently taken up by
- midasmatterhorn/artcraft-skillstheir own version, first seen Oct 17, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- midasmatterhorn/artcraft-skills★ 66same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository18 other files it gives its agents.
- cadcraftSkill
- craft-anythingSkill
- deckcraftSkill
- designcraftSkill
- effectcraftSkill
- figcraftSkill
- filmcraftSkill
- gridcraftSkill
- materialcraftSkill
- pdfcraftSkill
- photocraftSkill
- solidcraftSkill
- soundcraftSkill
- storytold-installSkill
- storytoldSkill
- texturecraftSkill
- vectorcraftSkill
- wordcraftSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 1 is distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 23
Use it for photographs as photographs:
- Very specific: line 46
If tools named mcp_lightcraft_* are available, use them.
- Very specific: line 81
Every edit is undoable (cmd_edit_undo / cmd_edit_redo).
- Very specific: line 319
If an --import fails, nothing runs: import failed for 1 item(s): […].
- Very specific: line 346
Use a separate --library for CLI work.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
LightCraft
LightCraft is a free, open-source clean-room take on Adobe Lightroom (storytold Crafting Apps): a photo
library plus a non-destructive raw developer. An agent drives it through an MCP server
(lightcraft-cli mcp) or one-shot CLI commands. Edits are settings stored per photo, never baked into the
original file. Pixels only change in an export. This skill is tested against LightCraft 0.18.1.
When to Use
Use it for photographs as photographs:
- developing RAW or JPEG photos: exposure, white balance, contrast, shadows/highlights, colour, B&W, crop, straighten
- the same look on many photos: presets, copy/paste or sync settings, batch export at a size and format
- culling and organising a shoot: ratings, pick/reject flags, colour labels, keywords, albums, finding duplicates
- local fixes: graduated / radial / sky / subject / luminance masks, dust spots, red eye
- HDR merges of brackets, panorama stitching (to DNG), and HDR output (gain map JPEG, PQ AVIF)
- a slideshow of a shoot as AV1 video, PDF or JPEG slides; print layouts (contact sheet, picture package) to PDF
Pick a different Crafting App when:
| The job is… | Use |
| Pixel-level retouching, layers, compositing several images, text on a photo | photocraft |
| Logos, icons, vector art, posters | vectorcraft |
| Photo books, brochures, multi-page layouts | designcraft |
| Video editing, slideshows with music or motion | filmcraft |
A typical hand-off: develop in LightCraft, then cmd_photo_editExternal {format: "psd"} (or export a 16-bit TIFF)
and composite in PhotoCraft.
Setup
- If tools named
mcp_lightcraft_*are available, use them. This is the preferred way. - Otherwise check for the CLI with
lightcraft-cli --version. If it's missing, load thestorytold-installskill and run itssetup lightcraft. Then ask the user to start a new session or run/reload-mcpso the MCP tools appear. - Until the MCP tools appear, use the CLI one-shots (see CLI below).
storytold-install registers the server as lightcraft-cli mcp --library <storytold data>/lightcraft-library.
The data folder is %LOCALAPPDATA%\storytold on Windows, or STORYTOLD_LIGHTCRAFT_LIBRARY when that's set.
It's headless (a full engine with a CPU renderer) and persistent, so imports, ratings and edits survive
between sessions. Bare lightcraft-cli mcp is in-memory: the library disappears when the server exits.
Your exported files stay, but the ratings and edits don't. Other modes:
lightcraft-cli mcp --library DIRopens or creates a persistent library in another folder, e.g. one per project.lightcraft-cli mcp --compactlists only the 17 helper tools; every command stays reachable viacommand_run.lightcraft-cli mcp --demostarts with a procedurally generated demo library (in memory);lightcraft-cli mcp FILES…imports those files or folders at start.lightcraft-cli mcp --connect 7980(a bare port means 127.0.0.1) drives a desktop app the user started withlightcraft --control 7980, so they can watch. Only this mode has the UI tools (screenshot,ui_screenshot,inspect_ui,ui_inspect,set_ui,click,press_key,type_text,clipboard,pointer_gesture,list_widgets). The server starts even when the app isn't running yet and connects on the first call.
Mental Model
- Library → photos with integer ids.
importadds files in place (it doesn't copy them unlessmode: "copy") and returns the new ids. Ids start at 1 in a new library and keep counting in a persistent one. - Active photo vs selection. Develop tools edit the active photo. Batch commands (
photo.rate, presets, export, sync) takeidsor fall back to the selection.select_photos {ids, active}sets both.doc_inspectshows them. - Develop settings are one JSON per photo (
get_develop). Sliders have ids likelight.exposure,wb.temp,mixer.blue.sat: 122 of them, inreferences/controls.md. The JSON uses snake_case (effects.dehaze,vignette.amount,detail.sharpen_amount). - Positions are normalized image coordinates, 0..1 with the origin at the top-left: crop rects, mask points, white-balance picks, spots.
- Every action is a command (383). Each one is also its own tool:
photo.rate→mcp_lightcraft_cmd_photo_rate, or usecommand_run {id, params}, orcommand_batch {steps}for several. Grepreferences/commands.md, orcommand_list {filter}. - Every edit is undoable (
cmd_edit_undo/cmd_edit_redo).cmd_history_list→{history, cursor}for the active photo;cmd_history_previous/cmd_history_next/cmd_history_restore {index}move the cursor.
Tools (Hermes names them mcp_lightcraft_<tool>)
| Tool | Use it for |
import {paths, mode?, destination?, organize?, rename?, album?, onDeleted?} | Files or folders (recursive). Returns imported ids plus duplicates and failed. The first new photo becomes active |
query_photos {filter?, sort?, limit?, offset?} | List photos: id, fileName, rating, flag, label, edited, kind (raw/image), format, size, keywords, total |
select_photos {ids, active?, mode?} | Selection and active photo. An unknown id is an error and changes nothing |
doc_inspect | Selection, active photo, filter, sort, undo label, plus counts |
list_controls {section?} | Sliders with min, max, default and current value for the active photo |
set_develop {id?, values?, settings?, label?} | values: {"light.exposure": 0.7} sets sliders. settings deep-merges develop JSON (label names that undo step) |
get_develop {id?} | The full develop JSON (plus process, the rendering process version) |
crop {id?, rect?, angle?, reset?} | rect: [x0,y0,x1,y1] normalized, angle in degrees (straighten) |
apply_preset {preset, ids?, amount?} | Preset ids from cmd_presets_list (lc.golden-hour…). amount 0..200 % |
render_preview {id?, max_side?, format?} | Look at the result. Long edge max_side (default 1024, max 4096). Never changes the selection |
render_photo {id?, size?, format?, path?} | Same, and path also saves the render to a file |
export {path | dir, id? | ids?, …} | Write files (see Export) |
command_list / command_run / command_batch / cmd_* | Everything else. list_commands / run_command {command} still work |
Resources: lightcraft://document (= doc_inspect), lightcraft://commands, lightcraft://library,
lightcraft://photos, lightcraft://photo/active, lightcraft://develop/active, lightcraft://controls. There are no prompts.
Develop
- Auto first, then refine:
cmd_develop_autosets exposure, contrast, highlights, shadows, whites, blacks, vibrance and saturation, overwriting those sliders. Run it before your own tweaks, not after. - Light:
light.exposure(−5..5 EV),light.contrast|highlights|shadows|whites|blacks(−100..100). - White balance:
cmd_develop_wb {mode: asShot|auto|daylight|cloudy|shade|tungsten|fluorescent|flash|custom, temp?, tint?}, orcmd_develop_wbPick {x, y}on something neutral. Lowerwb.temp= cooler/bluer result. On DNGs and raws LightCraft has colour matrices for,wb.tempis real Kelvin (get_developshowswb.scale: "kelvin"). On JPEGs and other raws it's relative: 6500 / 0 = as shot, so 4500 on a JPEG turns it blue. - Colour:
color.vibrance,color.saturation; HSL per colour band:mixer.<red|orange|yellow|green|aqua|blue|purple|magenta>.<hue|sat|lum>. - Tone curve: parametric
curve.highlights|lights|darks|shadows, or points:cmd_develop_curve {channel: master|red|green|blue, points: [[0,0.05],[0.25,0.2],[0.75,0.82],[1,1]]}.cmd_curve_presets/cmd_curve_applyPresetare named curves. - B&W:
cmd_develop_treatment {bw: true}(nobwtoggles), then thebw.<colour>mix orcmd_develop_autoBwMix. - Look:
grading.<shadows|midtones|highlights|global>.<hue|sat|lum>,effects.texture|clarity|dehaze,vignette.amount(negative darkens the corners),grain.amount,detail.sharpenAmount,detail.nrLuminance. - Profiles (the base rendering, plus LUTs):
cmd_profiles_list,cmd_develop_profile {id: "lc.vivid", amount}. - Crop and geometry:
crop {rect, angle}. A positiveangleturns the picture clockwise; the crop always stays inside the photo.cmd_crop_aspect {aspect: "16x9"|"1x1"|…},cmd_crop_autoStraighten,cmd_geometry_upright {mode: auto|level|vertical|full}. - HDR editing:
cmd_develop_hdr {enabled: true, maxEv?}lets highlights go above SDR white. Then export withhdr: true. Thehdr.sdr*sliders (hdr.sdrHighlights…) shape the SDR rendition that every normal render shows. - Reset:
cmd_develop_reset {ids?}(back to import defaults),cmd_develop_resetSection {section},cmd_develop_resetControl {control}. - Process versions:
cmd_develop_updateProcess {ids}moves photos on an older rendering process to the current one.
Masks and spot fixes
cmd_mask_add {kind, …} creates a mask and makes it active. cmd_mask_adjust {values} then sets its local
sliders: exposure, contrast, highlights, shadows, whites, blacks, temp, tint, texture, clarity, dehaze, hue,
saturation, sharpness, noise, moire, defringe, color_hue, color_sat, amount.
| kind | Params (normalized coordinates) |
linear | start: [x,y] (full effect) → end: [x,y] (none). Sky gradient: start [0.5,0], end [0.5,0.6] |
radial | center: [x,y], rx, ry (fractions of the photo), angle, feather 0..100 (default 50). Effect is inside |
luminanceRange | lo, hi 0..1 (default 0.6..1 = brights) |
colorRange | then cmd_mask_sampleColor {x, y} |
sky, subject, background | No params. These work without the AI model, but they're approximate, so render and check |
brush | cmd_mask_brushStroke {points, size} |
object {points, exclude?}, prompt {text} | Need the 3.4 GB SAM 3 model (cmd_segment_model_status). Ask the user before cmd_segment_model_download {acknowledged: true} |
Combine with cmd_mask_addComponent {op: add|subtract|intersect, kind, …}. Remove with cmd_mask_invert,
cmd_mask_delete or cmd_mask_deleteAll. Mask effect presets: cmd_mask_saveEffect {name, group?} stores the active mask's sliders,
cmd_mask_applyEffect {name} sets them on the active mask, cmd_mask_importEffects {paths} reads Lightroom / Camera Raw
local adjustment presets. Retouching: cmd_spot_findDust, cmd_spot_add {mode: heal|clone|remove|fill, points, size}
(fill is content-aware), cmd_redeye_add. cmd_spot_findBlemishes and cmd_faces_detect need the YuNet face
detector (232 KB, cmd_faces_models_download {id: "yunet-2023mar"}); ask before downloading.
Library, culling, batch
- Rate, flag, label:
cmd_photo_rate {rating, ids},cmd_photo_flag {flag: pick|reject|none, ids},cmd_photo_label {label: red|…, ids},cmd_photo_clearLabel {ids}.cmd_photo_cycleFlag/cmd_photo_increaseFlag/cmd_photo_decreaseFlag {ids}step each photo's own flag. - Metadata:
cmd_photo_setMeta {ids, title, caption, keywords: [..], creator, copyright},cmd_keyword_create {name, addToSelected?}. Tag many photos with the same keywords (tested):cmd_keyword_setShortcut {keywords: "beach, sunset"}, thencmd_keyword_toggleShortcut {ids}adds them (or removes them when every photo already has them) →{changed, keywords, added}. - Filter (
query_photos/cmd_catalog_query/cmd_library_filter):{rating: 3, ratingOp: "atLeast"|"exactly"|"atMost"},{flag: "pick"},{label: "red"},{keyword: "sky"},{kind: "raw"},{edited: true},{album: id},{merged: "any"},{text}.cmd_library_selectBy {rating|flag|label}selects directly. - Albums:
cmd_album_create {name, addSelected: true}→{id},cmd_album_addPhotos {id, ids},cmd_albums_list,cmd_album_createSmart {name, rules}. - Variants of one photo:
cmd_photo_virtualCopy {ids}(a new id with its own settings) orcmd_version_create {name}/cmd_version_restore {index}(named snapshots inside one photo). - Same look on many photos:
apply_preset {preset, ids}; or, from the active photo,cmd_develop_copy {groups?}andcmd_develop_paste {ids}; orselect_photos {ids, active: source}followed bycmd_develop_sync.cmd_develop_quickAdjust {control, delta, ids}nudges each photo from its own value. - Your own presets:
cmd_preset_create {name, group}(from the active photo) →{id: "user.…"}. Import Lightroom.xmp/.lrtemplatepresets withcmd_preset_import {paths}. A Lightroom Classic catalog:cmd_library_importLightroom {path}. - Assisted culling:
cmd_photo_analyze {ids, rejectBelow?, pickBest?}scores focus (0..100) and clipping.cmd_library_findSimilar,cmd_stack_auto. - Lens profiles:
cmd_lens_downloadDatabasefetches lensfun's lens database (CC BY-SA 3.0, a network download in the background; not tested);cmd_lens_databaseStatusshows it, andcmd_library_refreshLensProfiles {ids?, all?}re-reads lens profiles for raws once it's in place. - Contact sheet:
cmd_export_contactSheet {path: "/abs/sheet.pdf", ids, paper?: a4|letter, columns?, rows?, captions?}→{pages, photos}.
Procedure
- Import the files or folder and keep the ids (if
importedis empty, useduplicates[].existing). Cull if needed. - Develop one hero photo:
select_photos,cmd_develop_auto, thenset_develop, WB, crop and masks.render_preview {max_side: 800}after each major step: check exposure, colour cast, horizon and crop. - Spread the look with a preset, copy/paste or sync. Render a couple of them to check.
- Export and read each reply's
files[].path / width / height / bytes. To keep the edits themselves, use a persistent library or exportformat: "original"(the original plus an XMP sidecar).
Recipe: develop one photo (tested)
import {paths: ["/abs/shoot/IMG_0042.dng"]} → {imported: [1]}
cmd_develop_auto {}
set_develop {values: {"light.highlights": -60, "light.shadows": 50, "color.vibrance": 20}}
cmd_develop_wb {mode: "custom", temp: 5200, tint: 5}
crop {rect: [0.05, 0.08, 0.95, 0.92], angle: 1.5}
cmd_mask_add {kind: "linear", start: [0.5, 0], end: [0.5, 0.6]} → darken the sky
cmd_mask_adjust {values: {exposure: -1.0, saturation: 20}}
render_preview {max_side: 800} → look
export {path: "/abs/out/IMG_0042.jpg", longEdge: 2048, quality: 90}Recipe: cull and batch-export a shoot (tested)
import {paths: ["/abs/shoot"]}
cmd_photo_rate {rating: 4, ids: [1, 2]} · cmd_photo_flag {flag: "pick", ids: [2]} · cmd_photo_reject {ids: [4]}
query_photos {filter: {rating: 3, ratingOp: "atLeast"}} → ids [2, 1], total 2
apply_preset {preset: "lc.teal-orange", ids: [1, 2], amount: 80}
export {ids: [1, 2], dir: "/abs/out", naming: "{name}-{seq:2}", longEdge: 1600, quality: 85}
→ a_testsrc-01.jpg, b_gradient-02.jpg
cmd_export_contactSheet {path: "/abs/out/sheet.pdf", ids: [1, 2, 3, 4], columns: 3, rows: 2, captions: true}Recipe: B&W with HSL-driven tones, plus a colour variant (tested)
select_photos {ids: [1]}
set_develop {values: {"mixer.blue.hue": -60, "mixer.green.sat": -100}} → colour version
cmd_photo_virtualCopy {ids: [1]} → {ids: [2]}: inherits 1's settings, and is now active
cmd_develop_treatment {bw: true} → the copy turns B&W, 1 stays colour
cmd_develop_curve {channel: "master", points: [[0,0.1],[0.25,0.18],[0.75,0.85],[1,0.95]]}Recipe: HDR edit and HDR export (tested)
select_photos {ids: [1]} (a raw works best)
cmd_develop_hdr {enabled: true} → {enabled: true, maxEv: 3}
set_develop {values: {"light.exposure": 0.5, "hdr.sdrHighlights": -40}}
export {path: "/abs/out/a-hdr.jpg", hdr: true, longEdge: 2048} → JPEG with an ISO 21496-1 gain map
export {path: "/abs/out/a-hdr.avif", hdr: true} → 10-bit Rec. 2020 PQ AVIF
export {path: "/abs/out/a-hlg.avif", hdr: true, hdrTransfer: "hlg"} → 10-bit HLG AVIFRecipe: HDR merge of brackets (tested)
import {paths: ["/abs/brackets"]} → [1, 2, 3]
cmd_merge_hdr {ids: [1,2,3], preview: true, previewPath: "/abs/prev.png"} → check alignment, nothing written
cmd_merge_hdr {ids: [1,2,3], deghost: "low"} → writes bracket-0-HDR.dng next to the sources, imports it as id 4 (active)Panoramas (tested): cmd_merge_panorama {ids, projection: auto|cylindrical|spherical|perspective, autoCrop: true} → <first>-Pano.dng
(full resolution when memory allows). A whole shoot of brackets (tested): cmd_merge_hdrBatch {ids} merges each bracket set
(a stack, or photos less than a second apart at different exposures) → {merged: [{id, path, …}], failed}.
Recipe: slideshow to video and PDF (tested)
cmd_slideshow_templates_apply {id: "builtin:gallery-wall"} (built-ins: plain-black, gallery-wall, edge-to-edge,
cinema-wide, shooting-data; or set the parts yourself:)
cmd_slideshow_playback {slideDuration: 2, fadeDuration: 0.5}
cmd_slideshow_layout {margins: 0.05, backdropColor: "#202020", strokeBorder: true, strokeColor: "#ffffff"}
cmd_slideshow_overlays {addText: {text: "{name} · {date}", anchor: "bottom", size: 0.04}}
cmd_slideshow_titles {intro: {enabled: true, content: "text", text: "Summer 2026"}}
cmd_slideshow_preview {id: 1, width: 960, path: "/abs/slide1.png"} → look at one slide first
cmd_slideshow_export {format: "video", path: "/abs/show.mp4", ids: [1,2,4], size: "720p", wait: true}
→ AV1 MP4, 1280×720, 30 fps, no audio: the intro + 3 slides
cmd_slideshow_export {format: "pdf", path: "/abs/show.pdf", ids: [1,2,4], size: 1280, wait: true} → a page per slideformat: "jpeg" writes <name>-001.jpg… into the folder path; container: "webm" gives WebM. Need music or real
motion? Export the JPEG slides or the video and finish in FilmCraft.
Print layouts to PDF (tested): cmd_print_set {layout: {style: "contactSheet", page: {paper: "a4", orientation:
"portrait"}, grid: {columns: 2, rows: 2}}, image: {strokeEnabled: true}, job: {ppi: 240}}, then
cmd_print_exportPdf {path, ids} → {pages, photos}. Styles: singleImage|contactSheet|picturePackage|customPackage;
papers a3 a4 a5 letter legal tabloid 4x6 5x7 8x10 13x19, and the Japanese sizes l 2l kg postcard double-postcard 6cut
4cut business-card. A picture package: style: "picturePackage", then cmd_print_cell_add {width: 5, height: 3.5} per
cell (inches), and the photo fills every cell. cmd_print_get shows it.
Print templates (tested): cmd_print_template_save {name} stores the layout, image, page and job settings;
cmd_print_template_apply {name}. To share one: cmd_print_template_export {name, path} writes a .lcprint JSON file
(the extension is added when the path has none) and cmd_print_template_import {path} reads it back (a name taken gets " (2)").
Export
path(one photo, format from the extension) ordir+naming(batch; the folder is created). Tokens:{name} {num} {seq} {seq:N} {date:%Y%m%d} {folder} {camera} {lens} {iso} {rating} {title} {creator}.conflict: unique|overwrite|skip(default unique: a new name).destinationMode: "sameAsOriginal"writes each file next to its original instead of intodir.- Formats:
.jpg .png .tif .webp .avif .jxl .psd(a flat PSD), plusformat: "dng"(raws only: the raw at full size with the edits embedded; also what a.dngpath gives),format: "rendereddng"(Render to DNG: a linear 16-bit float DNG of the rendered photo with the edit baked in; works for any photo and honours the size) andformat: "original"(the file copied, plus an.xmpsidecar Lightroom can read). - Size: nothing = 3000 px long edge,
longEdge: 0= full size,longEdge|shortEdge|width+height|megapixels|percent. Withwidth+height,fit: "dimensions"(default) fits either orientation, so 500×800 on a landscape photo gives 750×500;fit: "widthHeight"caps the width and the height as the photo stands (500×333).dontEnlargedefaults to true, so a 1800 px photo stays 1800 px. - Options:
quality1..100,limitKb(JPEG fits a file size),colorSpace: srgb|displayP3|adobeRgb|proPhoto|rec2020,bitDepth(PNG 8/16, TIFF 8/16/32, PSD 8/16, AVIF 8/10, JXL 8/16; another value is an error:`bitDepth` must be 8 or 16 for png),tiffCompression: none|lzw|zip(default zip),metadata: all|allExceptCamera|copyright|none,removeLocation,sharpen: screen|matte|glossy,ppi,watermark: "text"or{text, anchor, size, opacity…},jxlLossless,hdr(see HDR editing),hdrTransfer: pq|hlg(HDR AVIF only; default pq). - Read: JPEG, PNG, TIFF, WebP, PSD composites, JPEG XL, HEIC, and raws: DNG, CR2, CR3, NEF, ARW, RAF (incl.
compressed and X-Trans), RW2/RWL, PEF, uncompressed ORF and SRW. Compressed ORF/SRW, Nikon HE NEF and a few CR3
variants open as embedded previews only (
previewOnlyinquery_photos). Raws of cameras without a fitted profile can start with muted colour. XMP sidecars are read on import.
CLI (no MCP needed)
lightcraft-cli render in.dng -o out.jpg --set light.exposure=0.3 --set light.shadows=40 --preset lc.golden-hour --size 1200
lightcraft-cli render in.dng -o out.tif --opt bitDepth=16 --opt colorSpace=adobeRgb # any app.export option
lightcraft-cli render in.jpg -o out.dng --opt format=rendereddng --size 2000 # a baked, linear DNG
lightcraft-cli render in.dng -o out.jpg --settings look.lcpreset --size 1600 # a preset.export file or XMP preset
lightcraft-cli run --import /abs/a.jpg develop.auto develop.set control=light.exposure value=0.7 \
app.export path=/abs/a-out.jpg longEdge=800 # one JSON line per command
lightcraft-cli run --library /abs/lib --import /abs/shoot photo.rate rating=5 'ids=[1,2]' # persists
lightcraft-cli run --library /abs/lib catalog.query 'filter={"rating":5}'
lightcraft-cli merge hdr|panorama|hdr-panorama|hdr-batch [--preview OUT.png] FILES… # hdr-batch: a folder works
lightcraft-cli run --script steps.jsonl # also JSON lines {"command": id, "params": {…}}
lightcraft-cli snapshot --library /abs/lib -o ui.png --size 1600x1000 # the full app UI, headless, as a PNG
lightcraft-cli synth-merge hdr|panorama -o /abs/dir # synthetic brackets (DNG) or pano views (PNG) to test with
lightcraft-cli commands --json · lightcraft-cli controls --json # the catalogsrun exits non-zero when a command fails (--keep-going continues). Words without = start the next command.
If an --import fails, nothing runs: import failed for 1 item(s): […]; no commands were run.
render --set refuses non-numbers: --set light.exposure: inf is not a finite number.
render writes .jpg .png .tif .webp .avif .jxl .psd .dng by extension.
Pitfalls
query_photos {filter: {minRating: 3}}(the example in itsfilterschema) is silently ignored and returns every photo. Use{rating: 3, ratingOp: "atLeast"}. Unknown filter keys never raise an error, so checktotal.set_develop,cropandexportwithidreplace the selection with just that photo.render_preview,render_photoandget_developwithiddon't change it. Re-select_photosbefore batch commands.- A duplicate import makes nothing active. Files already in the library (same path, or same content under another
name) come back as
duplicates: [{existing, reason: "path"|"content"}]withimported: [], and the next edit lands on whatever photo was active before. Select theexistingid first. cmd_photo_virtualCopymakes the copy active, so the next edit lands on the copy, not the original.cmd_develop_autooverwrites the light sliders and vibrance/saturation you set before it.- Values clamp silently:
light.exposure: 9becomes 5. An unknown id errors:invalid parameters fordevelop.set: unknown controllight.bogus``. set_develop {settings}answers{"controls": [], "ok": true}, even when it worked. Its keys are snake_case JSON. Confirm withget_develop.cmd_develop_copyleaves out crop, masks and spot removal by default. Passgroups(e.g.["crop"]).cmd_develop_synccopies to the selected photos. It returns{changed: 0}when only the active one is selected.command_batchstops at the first failing step (stop_on_errordefaults to true) and the whole call is an error; readresults[]to see which steps ran.- Helper tools refuse unknown keys with a protocol error (
unknown argument "bogusOpt" for export; expected: …). - One program per library. While the MCP server has its library open,
lightcraft-cli run --libraryon the same folder fails:This library is already open in lightcraft-cli 0.18.1 (process N). Close it there first.(followed by a hint to use--control PORTandmcp --connect). The same happens when the desktop app has it open; use--connectthen. Use a separate--libraryfor CLI work. kind: "prompt"/"object"masks without the model fail withThe SAM 3 model is not installed. Download it (about 3.4 GB, SAM License (Meta)) … withsegment.model.download {"acknowledged": true}….- AI Denoise has no bundled or downloadable model: on a raw
cmd_denoise_togglefails withAI Denoise needs a model: install one in Settings > AI Denoise; on a JPEG withAI Denoise applies to raw photos developed from their sensor data. Usedetail.nrLuminanceinstead. - A
.dngpath (orformat: "dng") only works for raws: a JPEG/PNG fails withb_gradient.jpg: DNG export needs a raw photo, and a raw comes out at full size whateverlongEdgesays. Useformat: "rendereddng"instead. - A merge writes its DNG next to the source files, so copy them first if that folder must stay untouched. An existing
name isn't overwritten: a second merge of the same brackets gives
bracket-0-HDR-2.dng. - Raws get default sharpening (40) and colour noise reduction (25); JPEGs get none.
- Paths: use absolute paths. Relative ones resolve against the server's working directory, not yours.
- Bad ids name the problem:
unknown commandphoto.nope, `unknown preset `nope,no such photo 9999,`ids` must be photo ids (whole numbers)(for"x"or-1). cmd_slideshow_exportwithoutwait: trueruns in the background. Pollcmd_slideshow_exportStatusuntilrunning: false. If the server exits first, only a.partfile is left behind.slideshow.*andprint.*settings are saved with the library and carry over to the next job. Set every key you care about, or start withcmd_print_reset/ a slideshow template.
Verification
render_previewand look at the image before you report the work as done. Compare it with a render taken before the edits.list_controls {section}orget_developshows the values actually stored (after clamping and auto).- Each
exportreply listsfileswithpath,width,height,bytes > 0. Count them against the ids you asked for. query_photos {filter: {edited: true}}lists the photos that really got edits.
References
${HERMES_SKILL_DIR}/references/commands.md: all 383 commands with params, grouped by area. Grep it rather than reading it whole, e.g.grep -n "mask\." ${HERMES_SKILL_DIR}/references/commands.md.${HERMES_SKILL_DIR}/references/controls.md: all 122 develop slider ids with ranges and defaults, by section. Grep it too.- Upstream docs: https://github.com/storytold/lightcraft/tree/main/docs (
mcp.md,control-protocol.md,ai-masks.md,merge.md,slideshow.md,xmp-interop.md,process-versions.md,faces.md,denoise.md).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

