photocraft
Skill36 starsChanged 11 days agoMITView on GitHub
Photo editing and compositing with PhotoCraft (Photoshop-style): retouch and color-grade photos, levels / curves / hue-saturation, layers and masks, selections, cut-outs, text on images, banners and thumbnails, resize / crop, filters, PSD files, data-driven variants from a CSV, batch-process folders. Export PNG / JPG / WebP / TIFF / PSD.
2 other projects use a version of this.
Adopted by
Most recently taken up by
- midasmatterhorn/artcraft-skillstheir own version, first seen Oct 17, 2026
- PBandDev/skillstheir own version, first seen Oct 15, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- midasmatterhorn/artcraft-skills★ 66same name
- PBandDev/skills★ 0same 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
- lightcraftSkill
- materialcraftSkill
- pdfcraftSkill
- solidcraftSkill
- soundcraftSkill
- storytold-installSkill
- storytoldSkill
- texturecraftSkill
- vectorcraftSkill
- wordcraftSkill
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 1 is distinctive, and 6 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.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 23
Use it for pixel work on one image (or a few) with layers:
- Very specific: line 44
If tools named mcp_photocraft_* are available, use them.
- Very specific: line 116
Read a pixel back with command_run document.pixel {x, y} → [r, g, b, a] in 0..1.
- Very specific: line 284
Only .pcraft keeps variables and data sets.
- Very specific: line 304
All of the above were run on 0.20.1.
- Very specific: line 329
Use a fresh dir or a prefix.
- Very specific: line 349
Every doc_save reply names the path.
≈ “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
PhotoCraft
PhotoCraft is a free, open-source clean-room take on Adobe Photoshop (storytold Crafting Apps). An agent
drives it through an MCP server (photocraft-cli mcp) or one-shot CLI commands. Documents keep real
layers, masks, adjustment layers, smart objects, live type and layer styles, and round-trip PSD files.
This skill was tested on PhotoCraft 0.20.1.
When to Use
Use it for pixel work on one image (or a few) with layers:
- retouching and colour-grading a photo, removing objects, healing spots, cut-outs and background removal
- composites: putting a logo, product or second photo onto a background, with masks, shadows and blend modes
- social graphics, banners, thumbnails and mockups built from photos plus text
- one template, many variants: a CSV of names / texts / visibility flags exported as one image per row
- resizing, cropping, converting, and opening or fixing
.psd/.psbfiles - applying the same edit to a folder of images (
photocraft-cli batch)
Pick a different Crafting App when:
| The job is… | Use |
| Developing RAW photos, culling a shoot, the same grade on many photos with a catalog | lightcraft |
| Logos, icons, illustrations that must scale; SVG / PDF vector output | vectorcraft |
| Multi-page layouts: brochures, magazines, books | designcraft |
| Animation, motion graphics, video compositing | effectcraft |
| Slides | deckcraft |
Setup
- If tools named
mcp_photocraft_*are available, use them. This is the preferred way. - Otherwise check for the CLI with
photocraft-cli --version. If it's missing, load thestorytold-installskill and run itssetup photocraft. Then ask the user to start a new session or run/reload-mcp. - File access needs roots.
storytold-installregistersphotocraft-cli mcp --automation-read-root <HOME> --automation-write-root <HOME>(HOME: the home folder, orSTORYTOLD_PHOTOCRAFT_ROOT). MCP paths are relative to HOME (Pictures/in.jpg) or absolute inside it (C:/Users/me/Pictures/in.jpg). A plainphotocraft-cli mcpcan still edit documents, but every file tool fails withautomation filesystem access is not granted: read authority is absent(orwrite authority). Then ask the user to runstorytold_tools.py register photocraft --replaceand/reload-mcp.PHOTOCRAFT_AUTOMATION_*_ROOTenv vars are not honoured bymcp(tested on 0.20.1). - Until then, use the CLI one-shots (see CLI): they take ordinary paths anywhere.
Headless (no desktop app) is a full engine with a CPU renderer; only the ui_* tools and control_call need
the live app. For the user to watch, they start photocraft --control 7878 --control-token-file <tok>
--automation-read-root <DIR> --automation-write-root <DIR>, and the server runs as
photocraft-cli mcp --bridge 127.0.0.1:7878 --control-token-file <tok>. The app's roots then apply: root flags
together with --bridge are a usage error (exit 2): error: configure automation roots on the desktop app;
--automation-read-root and --automation-write-root require headless MCP mode.
Mental Model
- Pixels, y down, origin at the canvas top-left. Type sizes are points; at the default 72 ppi 1 pt = 1 px.
- Session of documents.
doc_open/doc_newadd a document and make it active (indexin the reply);doc_select {index}switches; every command acts on the active document. - Layers have integer ids.
doc_inspectlists them top to bottom withid,kind,bounds[x, y, w, h],hasMask, blend, opacity;command_run layer.list {flat?}is the short version. Commands takelayer: id(or a layer name:layer.setProps {layer:"logo"}) and default to the active layer; a new layer becomes active. Ids are unique across the session, not per document (a fresh JPEG's Background is often id 2), and change when a file is reopened, so keep the ids replies give you. A wrong one fails with the list:no such layer 1; the document's layers are 2 "Background" (alayerparam takes an id or a name). - Every edit is an engine command (954).
command_run {id, params}runs one,command_batchseveral. Find ids withcommand_list {filter: "curves"}or grepreferences/commands.md. - Destructive vs non-destructive:
image.adjustments.*change the active pixel layer;layer.newAdjustmentLayer.*add an editable adjustment layer (change it later withlayer.setAdjustment). Filters andimage.adjustments.*on a smart object become editable smart filters. - Everything is undoable (
edit.undo/edit.redo);doc_inspectshowshistory. To experiment safely, runimage.duplicate {name}orhistory.newDocument {}first: both make a new active copy.
Tools (Hermes names them mcp_photocraft_<tool>)
| Tool | Use it for |
doc_open {path} / doc_new {width, height, background?, mode?, depth?, name?} | Open a file (under the read root) / new doc (default 1920×1080 white RGB 8-bit) |
doc_inspect {index?} | Layer tree with ids, bounds, masks, adjustments, text; selection, history, variables |
command_run {id, params?, wait?} | Any engine command. Returns its JSON result (often the new layer id) |
command_batch {steps:[{id, params}], stop_on_error?} | Several commands in one call; {completed, failed, results}. Not atomic: no rollback |
command_list {filter?, enabled_only?} | Command ids, menu path, param docs, enabled and disabledReason |
doc_render_preview {max_side?, index?} (alias render_preview) | Flattened PNG (default 1024 px, max 2048) so you can look at it |
doc_save {path?, quality?, tiffLayers?, tgaBits?, dpxBits?, ddsCompression?, ddsMipmaps?, format?} / doc_export | Save native .pcraft or export by extension (under the write root) |
doc_place {path, scale?, fit?, center?} | Place an image file as an embedded Smart Object layer |
doc_replace_smart_object {layer?, path} | Replace a Smart Object's contents from a file; keeps its transform and filters |
doc_export_layers {dir, format?, prefix?, quality?, visible_only?} | One file per layer (Layers to Files); refuses to overwrite; lists skipped layers |
doc_import_data_sets {path, delimiter?} / doc_export_data_sets {dir, format?, naming?, data_sets?} | Variable data sets from a CSV / one flattened file per data set |
session_list, doc_select {index}, doc_close {index?} | Manage open documents (close doesn't save; headless only). A bad index is an error: no document at index 9 |
jobs_list, jobs_cancel {job?} | Background jobs started with wait: false |
ui_inspect, ui_screenshot, ui_set, ui_menu_invoke, ui_pointer, control_call | Live app only (bridge mode) |
Resources: photocraft://document (same JSON as doc_inspect) and photocraft://commands (same as
command_list). No prompts. An unknown top-level tool argument is a JSON-RPC error
(unknown argument bogus for doc_open), but unknown keys inside params are still ignored.
Adjustments and colour
- Curves:
{points: [[0,0],[64,48],[192,210],[255,255]]}(0..255; per channel underred/green/blue). - Levels:
{inBlack, gamma, inWhite, outBlack, outWhite}(0..255, gamma 0.01..9.99; below 1 darkens). Curves and Levels also takeeyedropper: {point: "black|gray|white", at: [x, y]}to set points from the image. - Hue/Saturation
{hue, saturation, lightness, colorize}, Vibrance, Color Balance{midtones: [cr, mg, yb]}, Exposure, Photo Filter, Channel Mixer, Gradient Map{stops: [[0,"#000"],[1,"#fff"]]}, Color Lookup{lut: "tealOrange"}. - One-stop "Camera Raw" grade on a pixel layer:
filter.cameraRaw {temperature, exposure, contrast, highlights, shadows, clarity, vibrance, …}. - For black and white use
blackWhite(orchannelMixer {monochrome: true}), nothueSaturation {saturation: -100}, which turns every fully saturated colour into the same mid-grey. - Read a pixel back with
command_run document.pixel {x, y}→[r, g, b, a]in 0..1.
Selections and masks
select.rect {x, y, width, height, ellipse?, feather?, mode?},select.lasso {points},select.magicWand {x, y, tolerance},select.colorRange {points: [[x,y]], fuzziness},select.subject,select.sky, thenselect.modify.*,select.inverse,select.deselect.- An active selection becomes the mask of a new adjustment or fill layer (an active path becomes its vector
mask), and the selection is then gone (a
select.deselectafter it fails withcommandselect.deselectis not available right now: no selection). With no selection the mask is white. For other layers uselayer.layerMask.revealSelection(orhideSelection). layer.new.layerViaCopylifts the selection to a new layer (cut-outs).edit.fill {contents: "contentAware"}removes what's selected.layer.createClippingMaskclips the active layer to the one below.
Type
type.create {x, y, text, font, size, color, align?}:yis the baseline; withalign: "center"xis the centre of the line. Paragraph text:box: [x, y, w, h](wraps). Style afterwards withtype.setStyle {fontStyle: "Bold", tracking, leading, size, color, range?}.- A missing font (e.g. Helvetica on Windows) falls back, and the reply (and every
doc_save) carriesfont 'Helvetica' is not installed; text may render using a fallback face.type.fonts {family}lists a family's faces;type.resolveMissingFonts {}lists the document's missing families. Prefer fonts the OS has. - Type on a path (tested): draw the work path with
path.set {path:{subpaths:[{closed:false, knots:[{anchor:[100,380], in:[100,380], out:[250,80]}, {anchor:[700,380], in:[550,80], out:[700,380]}]}]}},type.create(itsx/ydon't matter), thentype.attachToPath {start:40}. Around a shape:type.attachToPath {layer, shape:<shape layer id>, flip?}(another id:"shape" is not a shape layer).type.detachFromPathreleases it. Survives a PSD round trip.
Procedure
- Plan the output size, the layer stack (background → photo → adjustments → type), and the deliverables.
- Open or create:
doc_open/doc_new, thendoc_inspectto get layer ids. - Edit non-destructively: adjustment layers, masks, smart objects, layer styles, type layers.
- Look:
doc_render_preview {max_side: 800}after each major step, and check the image. Check numbers withdoc_inspect(bounds,hasMask) ordocument.pixel. - Save the editable master (
.psdfor others,.pcraftnative), then export flat deliverables and read each reply'swarnings.
Recipe: photo grade with vignette, resize and export (tested)
doc_open {path:"shoot/photo.jpg"} → Background id from doc_inspect
command_run layer.newAdjustmentLayer.curves {points:[[0,0],[64,48],[192,210],[255,255]]}
command_run layer.newAdjustmentLayer.hueSaturation {saturation:-20}
command_run select.rect {x:400, y:200, width:800, height:500, ellipse:true, feather:120}
command_run select.inverse
command_run layer.newAdjustmentLayer.levels {gamma:0.5} → the selection becomes its mask (and is used up): dark edges only
command_run layer.select {layer:<Background id>} → filters need a pixel layer
command_run image.crop {x:200, y:100, width:1200, height:800}
command_run image.imageSize {width:900, height:600, resample:"lanczos"}
command_run filter.sharpen.unsharpMask {amount:80, radius:1.2, threshold:2}
doc_render_preview {max_side:900} → check
doc_save {path:"out/photo.psd"} · doc_save {path:"out/photo.jpg", quality:88}image.crop also takes targetWidth/targetHeight to crop and resample in one step.
Recipe: logo / product composite (tested)
doc_open {path:"bg.jpg"} → index 0
doc_place {path:"logo.png", scale:50, center:[250,700]} → embedded Smart Object, {layer, bounds:[x0,y0,x1,y1]}Or copy pixels from another open document:
doc_open {path:"logo.png"} → index 1
command_run select.all · command_run edit.copy → {bounds} of what was copied
doc_close {} · doc_select {index:0} → the clipboard survives the close
command_run edit.paste {center:[800,450]} → {layer, offset}; without center (or if larger than the canvas) it lands at (0,0)
command_run layer.setProps {name:"Logo", opacity:1, blend:"Normal"}
command_run edit.transform {quad:[[600,250],[1000,250],[1000,650],[600,650]]} → scale/position exactly
command_run layer.layerStyle.dropShadow {color:"#000000", distance:10, size:20, opacity:60}
doc_render_preview {} · doc_save {path:"out/comp.psd"} · doc_save {path:"out/comp.png"}
doc_export_layers {dir:"out/layers"} → comp_0000_<layer>.png … (dir must not hold those names)edit.transform maps the layer's source frame onto quad; its reply rect is that source frame. For a relative
change use edit.transform {scaleX:50, scaleY:50, rotate:30, dx:50, dy:0} (percent, degrees, about the frame's
centre, then moved) (tested).
Recipe: banner with photo-filled text (tested)
doc_new {width:1200, height:630, background:"#101820", name:"banner"}
command_run layer.newFillLayer.gradient {from:"#ff5f6d", to:"#ffc371", angle:0, style:"linear"}
command_run type.create {x:600, y:380, text:"FRACTAL", font:"Arial", fontStyle:"Bold", size:220,
color:"#ffffff", align:"center"}
(copy a photo from another open doc as above) → command_run edit.paste {center:[600,315]}
command_run layer.createClippingMask → photo shows only inside the letters
doc_render_preview {} · doc_save {path:"out/banner.png"}Recipe: one image per CSV row (variable data sets) (tested)
doc_new {width:800, height:400, background:"#203040", name:"card"}
command_run type.create {x:400, y:220, text:"Title", font:"Arial", size:80, color:"#ffffff", align:"center"} → layer 3
command_run shape.create {kind:"ellipse", rect:[680,30,80,80], fill:"#ffcc00"} → layer 4
command_run image.variables.define {defs:[{name:"title", layer:3, type:"textReplacement"},
{name:"badge", layer:4, type:"visibility"}]}
doc_import_data_sets {path:"in/cards.csv"} → {imported:2}
doc_export_data_sets {dir:"out/cards", naming:"card_{name}"} → out/cards/card_alice.png, card_bob.png
doc_save {path:"out/card.pcraft"} → keeps the variables (PSD does not)cards.csv (header = variable names; an empty first header makes column 1 the data-set name, otherwise
sets are named Data Set 1, Data Set 2…):
,title,badge
alice,Hello Alice,true
bob,"Hi, Bob",falseVariable types: textReplacement, visibility (true/false), pixelReplacement. Preview one with image.applyDataSet {name}.
Recipe: annotate a photo with an arrow and area type (tested)
doc_open {path:"shoot/photo.jpg"}
command_run shape.create {kind:"line", from:[300,700], to:[750,420], weight:12, arrowEnd:true,
arrowWidth:60, arrowLength:60, fill:"#ffffff"} → live arrow line, editable with shape.edit
command_run shape.create {kind:"ellipse", rect:[900,150,500,500], fill:"#203040"} → layer 4
command_run type.create {x:0, y:0, text:"Long caption …", font:"Arial", size:40, color:"#ffffff"}
command_run type.fillPath {shape:4} → the text wraps inside the ellipse (Area Type)
doc_render_preview {}arrowStart, arrowConcavity (0..100) shape the heads. Without shape, type.fillPath uses the work path.
More building blocks
- Edit a smart object's contents (tested):
layer.smartObjects.editContents {layer}opens the contents as a new active document → edit it →layer.smartObjects.saveContents→doc_close {}. The parent updates in memory. - Swap a smart object's file (tested):
doc_replace_smart_object {layer, path:"shoot/new.jpg"}→{instances, layer, warnings}. Scale, top-left corner and smart filters stay; a bigger file makes a bigger layer. - Video frames over MCP (tested):
timeline.create {}thencommand_run file.export.renderVideo {dir:"out/frames", format:"png"}→{dir, frames}(<doc>_0000.png…). The onlyfile.export.*MCP allows, and only headless. - Several layers in one step:
layer.setProps {layers:[6,7], opacity:0.5}(tested). Faces:image.detectFaces. - Rotated crop, corners filled (tested):
image.crop {x:-100, y:0, width:1700, height:900, angle:5, contentAware:true}. - Text with effects:
layer.layerStyle.dropShadow | stroke | outerGlow | colorOverlay | gradientOverlay | bevelEmboss. - Arrange:
layer.translate {dx, dy},layer.moveTo {target, position},layer.arrange.bringToFront,layer.align.horizontalCenters {to: "canvas"}(selected layers; select withlayer.select {layer, mode:"add"}). - Canvas:
image.canvasSize {width, height, relative, anchor, extensionColor},image.trim,image.imageRotation.90cw,image.mode.grayscale/cmyk,image.mode.bits16. - Retouch:
paint.spotHealing {points, size},paint.cloneStamp {points, source},paint.remove,edit.contentAwareFill. - Paint:
paint.stroke {points:[[x,y,pressure],…], size, color, hardness},paint.gradient {from, to, colors}. Actions:actions.record→ edits →actions.stop, thenactions.getgives steps forbatch. - Photoshop .atn (tested):
actions.save {action}returns the.atnas base64data(forbatch --actions x.atn);actions.load {data}loads one,actions.play {action}runs it. Unplayable Photoshop steps fail at playback with their name.
Formats
- Read and write:
.pcraft(native, lossless), PSD, PSB, layered or flat TIFF, PNG, JPEG, WebP, GIF, BMP, TGA, ICO, QOI, PNM, OpenEXR, Radiance HDR, AVIF, DPX, DDS; Cineon (.cin) and HEIC (optional build feature) read-only. SVG opens as shape layers and places as a vector smart object. - PDF is write-only (tested):
doc_save {path:"out/x.pdf"}writes one flattened page (warningPDF was saved flattened: …); PhotoCraft can't open it again (codec: unrecognized image format). doc_savepicks the format from the extension (formatoverrides).quality1..100 for JPEG / WebP (WebP withoutqualityis lossless).tiffLayers: truekeeps layers in TIFF;tgaBits: 24|32for TGA;dpxBits: 8|10|12|16for DPX (default 8 for an 8-bit document, else 16);ddsCompression: "none|bc1|bc2|bc3"andddsMipmaps: truefor DDS textures (tested: bc3 with mipmaps re-opens and reads in ffprobe).doc_save/doc_exportreplace an existing file only if it is an image or document file; otherwiseautomation write refused:out/notes.txtalready exists and is not an image or document file PhotoCraft writes; save to a new name.- PSD /
.pcraftkeep layers, masks, adjustment layers, smart objects, smart filters and type (tested round trip). Only.pcraftkeeps variables and data sets. Flat formats return the warningN layer(s) flattened; layers, masks and blend modes are not kept; JPEG addslossy compressionand composites transparency over white.
CLI (no MCP needed; any path works)
photocraft-cli info file.psd --compact # JSON: size, mode, depth, layer tree
photocraft-cli convert in.psd out.jpg --quality 85 # any supported format to any other (also .pdf, .dds)
photocraft-cli run in.jpg --cmd image.adjustments.curves --params '{"points":[[0,0],[70,50],[190,215],[255,255]]}' \
--cmd image.imageSize --params '{"width":800,"height":500}' --out out.jpg --quality 90
photocraft-cli run --new '{"width":600,"height":400,"background":"#223344"}' \
--cmd type.create --params '{"x":300,"y":220,"text":"Hi","size":120,"color":"#ffcc00","align":"center"}' --out t.png
photocraft-cli batch --actions steps.json --in ./photos --out ./graded --format jpg --quality 80
photocraft-cli batch --actions grade.atn --action Grade --in ./photos --out ./graded # a Photoshop .atn set
photocraft-cli run --new '{"width":10,"height":10}' --cmd file.automate.createDroplet \
--params '{"path":"grade.pcdroplet","steps":[["image.imageSize",{"width":320,"height":180}]],"format":"png"}'
photocraft-cli droplet grade.pcdroplet a.jpg ./photos --out ./small # files and folders
photocraft-cli commands --filter blur # the command catalog (--json for all fields)All of the above were run on 0.20.1. steps.json is [["image.adjustments.hueSaturation", {"saturation": -30}],
{"command": "image.imageSize", "params": {…}}]; an Actions-panel set ({"actions":[{name, steps}]}) also works,
with --action <name>. batch refuses --out equal to --in unless --in-place, and exits 1 if any file failed. convert and run
refuse an output that is the input file the same way (error: out/same.jpg is the input file, so the result would
replace the original: choose another output, or pass --in-place to overwrite it). run also takes
--tiff-compression none|lzw|zip, --jpeg-format baseline|optimized|progressive, --dds-compression, --dds-mipmaps.
createDroplet on macOS also writes a grade.command shim next to the droplet. A droplet given two inputs with the
same name fails the second: not written: ./small/photo.png already holds the result of shoot/photo.jpg from this run
(same output name).
run also allows the path-taking commands MCP refuses, e.g. file.placeEmbedded {path, scale} and
file.export.layersToFiles {dir} (tested). photocraft-cli serve keeps one headless session open over JSON lines.
Pitfalls
- Paths over MCP must be under the roots. Relative paths use forward slashes (
automation path rejected: alternate separators are not allowed; use/``), no..(parent traversal is not allowed), no~. An absolute path outside the root fails withautomation path rejected: absolute paths must be inside the automation root. The output folder must exist: otherwiseI/O: automation write…failed (NotFound). - Path-taking commands are refused over MCP (
file.placeEmbedded,file.saveACopy, everyfile.export.*includingfile.export.presets.list,actions.load|save {path}, …):automation commandfile.placeEmbeddeduses ambient filesystem paths and is disabled; use capability-scoped document methods. Usedoc_open,doc_save,doc_place,doc_export_layers, the data-set tools, or the CLIrun. doc_savewith nopathonly writes back PSD / PSB / .pcraft / OpenRaster. On a JPEG:passpath: without one, only a PSD, PSB, .pcraft or OpenRaster file that holds the whole document is written back, ….doc_export_layersnever overwrites:I/O: automation create exportcomp_0000_logo.pngfailed (AlreadyExists). Use a freshdiror aprefix.- Unknown command params are mostly ignored silently (
image.imageSize {widht:100}is a no-op that still adds anImage Sizehistory step;layer.setProps {bogus:1}too). Few commands check (layer.hideLayers {bogus:1}:invalid parameters forlayer.hideLayers: unknown parameterbogus…). Compare the reply with your request. - Filters and
image.adjustments.*need a pixel layer. A new adjustment or type layer becomes active, so the next filter fails withfilters need a pixel layer (active layer is an Adjustment layer).layer.selectfirst.batchfails the same way on a PSD saved with an adjustment layer active (… not a pixel layer). - Bounds formats differ:
doc_inspectgives[x, y, w, h];type.create,edit.transformanddoc_placegive[x0, y0, x1, y1]. wait: falselocks the document until the job ends: other commands fail with“Gaussian Blur” is still running on this document; wait for it to finish or cancel it (Esc). Keep the default (wait) unless you polljobs_list.- PSD drops variables and data sets without a warning; save
.pcraftto keep them. - Bridge mode:
doc_render_previewreturns a screenshot of the app window, not the image. Export a PNG to check pixels.doc_closefails: ``doc_closeis only available in headless mode (in the GUI use the window/tab UI or control_call). (Checked on 0.10.0; bridge mode not re-tested on 0.20.1.)
Verification
doc_render_preview, then look at the image before you report the work as done.doc_inspect: the expected layers,hasMask, adjustment values, text, and canvaswidth/height.- Every
doc_savereply names thepath; read itswarnings(flattening, lossy, missing fonts).photocraft-cli info <file>confirms a saved file re-opens with its layers.
References
${HERMES_SKILL_DIR}/references/commands.md: all 954 engine commands with params, grouped by area (layer.newAdjustmentLayer,filter.blur,select,type,image.variables…). Grep it rather than reading it whole, e.g.grep -n "unsharp" ${HERMES_SKILL_DIR}/references/commands.md.- Upstream docs: https://github.com/storytold/photocraft/tree/main/docs (
mcp.md: tools, resources, batch recovery, smart objects;control-protocol.md: control methods, automation roots, background jobs, headlessserve).
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.

