# io.github.editmamei/editmamei (npm · editmamei)

Photoshop MCP server: natural-language AI photo editing in desktop Photoshop. AI orchestration.

- Trust score: 88/100 (high trust)
- Change this week: 0
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-09-20

## Components

- npm · `editmamei`: 88/100 (this document), [markdown](https://verifymcp.io/servers/editmamei-editmamei/editmamei.md), [page](https://verifymcp.io/servers/editmamei-editmamei/editmamei)

## Channel facts

- Registry: `npm`
- Package: `editmamei`
- Version: `1.5.0`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-09-20.

- **Supply Chain Security**: 98/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - No install/post-install scripts declared.
  - 39 of 115 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 87/100
  - Source repository is publicly reachable at the declared URL.
  - Cryptographically verified build provenance (signed, bound to editmamei/editmamei).
  - License check failed: the license (FSL-1.1-MIT) isn't a recognized OSI-approved license.
  - Actively maintained (last published 1 days ago).
  - Publishes a security disclosure policy (SECURITY.md).
- **Schema Quality & AI Usability**: 59/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 28680 tokens (~462/item across 62 items; 62 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 88/100
  - Stability check failed: the tool surface changed between 1.1.0 and 1.5.0: 8 tool removals, 0 breaking changes, 3 additions.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
  - Structured output schemas are declared (100% of tools); any adoption earns full credit.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - All 2 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.
  - An AI judge read all 62 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### How do I install the io.github.editmamei/editmamei MCP server?

io.github.editmamei/editmamei runs locally as an npm package, launched with npx -y editmamei. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add editmamei-editmamei -- npx -y editmamei
```

### Cursor

```json
{
  "mcpServers": {
    "editmamei-editmamei": {
      "command": "npx",
      "args": [
        "-y",
        "editmamei"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "editmamei-editmamei": {
      "command": "npx",
      "args": [
        "-y",
        "editmamei"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add editmamei-editmamei -- npx -y editmamei
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "editmamei-editmamei": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "editmamei"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add editmamei-editmamei --command npx --arg -y --arg editmamei
```

### Hermes

```yaml
mcp_servers:
  editmamei-editmamei:
    command: "npx"
    args: ["-y", "editmamei"]
```

### Netclaw

```json
{
  "McpServers": {
    "editmamei-editmamei": {
      "Transport": "stdio",
      "Command": "npx",
      "Arguments": [
        "-y",
        "editmamei"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add editmamei-editmamei -t stdio -c npx -a -y editmamei
```

### Other

```json
{
  "mcpServers": {
    "editmamei-editmamei": {
      "command": "npx",
      "args": [
        "-y",
        "editmamei"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-09-20 (score 88, +1)

No change was recorded against any check on this day. Stability & Change Management went from 85 to 88.

### 2026-09-19 (score 87, +26)

- [security improvement] Malware scan: unverified → pass
- [security improvement] Judged manipulation: unverified → pass
- [functional improvement] Schema quality: unverified → excellent

### 2026-09-18 (score 61, −25)

- [security regression] Judged manipulation: pass → unverified
- [security regression] Malware scan: pass → unverified
- [functional regression] Schema quality: excellent → unverified
- [functional] Package version: 1.4.0 → 1.5.0

### 2026-09-16 (score 86, +1)

No change was recorded against any check on this day. Stability & Change Management went from 71 to 75.

### 2026-09-14 (score 85, −3)

No change was recorded against any check on this day. Stability & Change Management went from 88 to 68.

### 2026-09-13 (score 88, +1)

- [security improvement] CVE-2026-76845 no longer affects this package
- [security improvement] Known CVEs: partial → pass

### 2026-09-10 (score 87, +1)

No change was recorded against any check on this day. Stability & Change Management went from 79 to 83.

### 2026-09-09 (score 86, 0)

- [security regression] CVE-2026-76845 affects this package
- [security regression] Known CVEs: pass → partial

## MCP tools (62)

### `ps_ping` (~182 tokens)

Test connection to Photoshop and report session-start discovery signals. Read-only and idempotent. Call this once at the start of a session to confirm liveness before invoking any other tool. **If the user has given you an open-ended editing task, ALSO call `ps_overview` after this** — it returns the workflow contract + capabilities map + verification primitives so you can plan well. Returns `version` (folds the removed get-version tool), `custom_action_sets` (count of Action Sets loaded in the Photoshop Actions palette — non-zero means recorded workflows exist; if action tools are available in this build they will appear in `tools/list`), `user_templates` (count of saved Editmamei templates), and `open_documents` (names of documents already open in Photoshop, so the LLM does not have to ask which doc to edit).

Output parameters:

- `connected` (boolean)
- `custom_action_sets` (number)
- `degraded` (array): List of optional discovery signals that could not be gathered (e.g. "pingState" if the go-core snippet builder itself failed to produce the in-PS state script — a broken/missing local install, unrela…
- `notify_user` (boolean): True on the one ping whose text carries the update notice — relay that notice to the user before continuing. False on later pings and when no update is available.
- `open_documents` (array)
- `update_available` (object|null): Set when a newer Editmamei version is published, else null: { current, latest, channel (npm/mcpb/dev), how_to_update, fixed_tools (tools whose recorded failures the newer version fixes) }. The relay…
- `user_templates` (number)
- `version` (string)

### `ps_list_capabilities` (~111 tokens)

Live map of every tool this MCP exposes, grouped by capability — each group is a one-line purpose plus the tool names in it. Read-only and cheap. Reach for it to re-orient mid-session (what exists, what to reach for) when the overview brief has scrolled out of context, or to learn which tool names to look up. ps_overview tells you HOW to combine tools; this tells you WHAT exists, currently; tools/list has the full schema for any one you pick.

Output parameters:

- `group_count` (number)
- `groups` (array)
- `tool_count` (number)

### `ps_create_document` (~109 tokens)

Create a new empty Photoshop document with given dimensions, resolution, and color mode. Returns the new document id and name plus active context. Use this when starting from scratch; prefer ps_open_document to load an existing file.

Input parameters:

- `color_mode` (string): Color mode (RGB, CMYK, Grayscale)
- `height` (number, required): Document height in pixels
- `resolution` (number): Document resolution in DPI (default: 72)
- `width` (number, required): Document width in pixels

Output parameters:

- `context` (object)
- `id` (number)
- `name` (string)

### `ps_document` (~257 tokens)

See and steer WHICH documents are open, without touching their content. op=list answers 'what is open, which one is active, and does it have unsaved changes' — and it is the one document tool that works when nothing is open at all, so it is the recovery read after a 'No document is open' failure. op=activate switches the active document by name or id, which is how you fix having edited the wrong one. Read-only with respect to pixels; use ps_open_document to load a file and ps_close_document to close one.

Input parameters:

- `id` (integer): Target an open document by its Photoshop document id. Unambiguous — prefer this when names collide.
- `name` (string): Target an open document by its exact Photoshop name, INCLUDING the extension as shown in the tab (e.g. 'portrait.jpg', not 'portrait'). If two open documents share a name the call fails rather than g…
- `op` (string, required): list: every open document (index, id, name, path, saved, active, dimensions) — safe to call when NOTHING is open, which is the point. activate: make one of them the active document, by name or id.

Output parameters:

- `activated` (boolean)
- `context` (object)
- `count` (number)
- `documents` (array)
- `id` (number)
- `name` (string)
- `op` (string)

### `ps_close_document` (~172 tokens)

Close a Photoshop document — the active one by default, or a specific one by name or id. Destructive if save=false and the document has unsaved changes. If two open documents share the requested name the call fails rather than guessing. Returns the closed document name plus a fresh context block (which document, if any, is active afterwards).

Input parameters:

- `id` (integer): Target an open document by its Photoshop document id. Unambiguous — prefer this when names collide.
- `name` (string): Target an open document by its exact Photoshop name, INCLUDING the extension as shown in the tab (e.g. 'portrait.jpg', not 'portrait'). If two open documents share a name the call fails rather than g…
- `save` (boolean): Whether to save changes before closing

Output parameters:

- `closed` (boolean)
- `closedName` (string)
- `context` (object)
- `saved` (boolean)

### `ps_open_document` (~310 tokens)

Open a file from disk into Photoshop with all dialogs suppressed (uses last-used Camera Raw settings for raw/HEIC). Returns document name, dimensions, color mode, and whether the source was a raw format. `is_raw_source` is workflow-critical, not a passive status field: when true, the first edit should be a Camera Raw develop pass on the base smart object (via a camera-raw develop tool, if one is registered in tools/list) — NOT stacked tonal adjustment layers. Use this in the pipeline to load Inbox files for editing. If the file is ALREADY open, its existing document is activated rather than opened a second time — `already_open: true` says so, and any edits made to it are still there (Photoshop would otherwise open a duplicate with a fresh Background, which silently strands prior work).

Input parameters:

- `bit_depth` (number): Open-time bits per channel, RAW sources only. Set this here rather than converting later: ps_convert_image_mode FLATTENS the document, so depth cannot be changed once an edit stack exists. Prefer 16…
- `file_path` (string, required): Absolute path to the file to open
- `suppress_dialogs` (boolean): Suppress all PS dialogs during open (raw/HEIC use last-used ACR settings). Default true for pipeline use.

Output parameters:

- `already_open` (boolean)
- `bit_depth_warning` (string): Present only when a requested bit_depth was not what the document actually opened at — because the file is not a raw source, or Photoshop declined the requested depth. Absent means bits_per_channel i…
- `bits_per_channel` (number)
- `color_mode` (string)
- `context` (object)
- `document_name` (string)
- `file_path` (string)
- `height_px` (number)
- `is_raw_source` (boolean): True when the source file was a raw capture (DNG/NEF/CR3/ARW/…). Workflow-critical: the open used last-used/default Camera Raw settings, so no deliberate develop has happened yet. When true, run the…
- `resolution` (number)
- `success` (boolean)
- `width_px` (number)

### `ps_save_psd` (~254 tokens)

Save the active document as a layered PSD to the given path. Saves as a copy, so the working document is unmodified and unrenamed. Use this in the pipeline to land an editable PSD into the Edit folder.

Input parameters:

- `keep_scene_channels` (boolean): Keep the managed scene:* alpha channels ps_read_scene precomputes. Default false — they are DERIVED masks (rebuilt by the next scene read) and each is a full-resolution channel, so baking them into t…
- `maximize_compatibility` (boolean): Include flattened composite for compatibility with other apps. Default true.
- `output_path` (string, required): Absolute output path including filename, e.g. E:\Photos\Edit\shell_01.psd

Output parameters:

- `context` (object)
- `document_name` (string)
- `layers` (number)
- `saved_to` (string)
- `success` (boolean)

### `ps_export` (~347 tokens)

Export the active document to a flattened image file — JPEG or PNG, chosen via `format`. Operates on a duplicate, so the working document is unchanged. Optionally downscales so the long edge equals long_edge_px. JPEG: quality 0-100 (Save-As scale), optional sRGB convert + profile embed. PNG: transparent background (alpha preserved) or flattened onto white, compression 0-9.

Input parameters:

- `compression` (integer): PNG compression level 0-9. Lower = larger file, faster. Default 6.
- `convert_to_srgb` (boolean): Convert to sRGB before export. Default true.
- `embed_color_profile` (boolean): Embed color profile in the exported file. Default true.
- `format` (string, required): Output image format. jpeg: quality 0-100, optional convert_to_srgb + embed_color_profile. png: transparent_background (alpha) or flattened-on-white, compression 0-9. Both take output_path (required)…
- `long_edge_px` (integer): Resize so the longest edge equals this value. Omit for full resolution. Downscale only.
- `output_path` (string, required): Absolute output path including filename.
- `quality` (integer): JPEG quality 0-100 (the Photoshop 'Save As' / JPEG-dialog scale humans and the UI use). 100 = maximum. Mapped internally to Photoshop's 0-12 JPEGSaveOptions scripting scale (e.g. 90→11, 100→12).
- `transparent_background` (boolean): If true, preserves transparency. If false, flattens onto white. Default false.

Output parameters:

- `context` (object)
- `exported_to` (string)
- `height_px` (number)
- `quality` (number)
- `quality_ps_scale` (number)
- `success` (boolean)
- `transparent` (boolean)
- `width_px` (number)

### `ps_create_layer` (~57 tokens)

Create a new empty raster layer above the currently active layer. Non-destructive. Use ps_text (op=create) for text, ps_add_adjustment_layer for adjustments.

Input parameters:

- `name` (string): Name for the new layer (optional)

Output parameters:

- `context` (object)
- `created` (boolean)
- `layerName` (string)
- `parent_path` (array|null): The containing-group name chain (outermost first), empty array at the document root.

### `ps_delete_layer` (~137 tokens)

DESTRUCTIVE: Delete a layer. With no arg, deletes the currently active layer (backward-compatible). With `name`, recurses into groups and deletes the first LAYER matching that name — useful for cleanup workflows where the dead layer is not currently active. A name that matches a group is refused rather than deleted; use ps_group(op=delete) to delete a group and all its contents. Recoverable only via Edit > Undo.

Input parameters:

- `name` (string): Optional layer name. If supplied, recurses into groups and deletes the first layer matching this name. If omitted, deletes the currently active layer (backward-compatible).

Output parameters:

- `context` (object)
- `deleted` (boolean)
- `layerName` (string)

### `ps_fill_layer` (~90 tokens)

Fill the active layer (or the current selection within it) with a solid RGB color. Idempotent for the same color. Throws on fully-locked or text layers — rasterize text first if needed.

Input parameters:

- `blue` (integer, required): Blue component (0-255)
- `green` (integer, required): Green component (0-255)
- `red` (integer, required): Red component (0-255)

Output parameters:

- `color` (object)
- `filled` (boolean)
- `layerName` (string)

### `ps_add_fill_layer` (~611 tokens)

Add a non-destructive SOLID COLOR or GRADIENT fill layer (an editable content layer — distinct from ps_fill_layer, which bakes color into the active pixel layer). fill_type=gradient is the go-to for sky fades, color washes, and vignettes (radial + reverse + multiply blend); combine with opacity_stops 100→0 for fade-to-transparent, or ps_bake_layer to rasterize. For fading a layer out via its MASK use ps_layer_mask op=gradient instead. Hoisted out of the active layer's group by default (pass into_active_group:true to keep Photoshop's native nesting). The new fill layer becomes active.

Input parameters:

- `angle` (number): fill_type=gradient: gradient angle in degrees (Photoshop convention: 90 runs the first stop from the bottom up; 0 runs it left to right).
- `blue` (integer): fill_type=solid_color: blue (0-255). Required for solid_color.
- `dither` (boolean): fill_type=gradient: dither to reduce banding.
- `fill_type` (string): Fill-layer type. solid_color takes red/green/blue (required for that type); gradient takes the gradient_* params + stops (pattern fills still planned).
- `gradient_type` (string): fill_type=gradient: gradient geometry. linear for skies/fades, radial for vignettes/glows.
- `green` (integer): fill_type=solid_color: green (0-255). Required for solid_color.
- `into_active_group` (boolean): Photoshop's Mk-contentLayer descriptor carries no placement target, so with a GROUP active it would natively nest the new fill layer INSIDE that group. Default false hoists the new layer back out so…
- `offset_x` (number): fill_type=gradient: horizontal center offset percent.
- `offset_y` (number): fill_type=gradient: vertical center offset percent.
- `opacity_stops` (array): fill_type=gradient: opacity stops, each {opacity (0-100), location (0-100), midpoint (5-95, default 50)}. Use e.g. 100→0 for a fade-to-transparent wash. Default: fully opaque.
- `red` (integer): fill_type=solid_color: red (0-255). Required for solid_color.
- `reverse` (boolean): fill_type=gradient: reverse the stop order.
- `scale` (number): fill_type=gradient: gradient scale percent (compress/stretch the ramp).
- `stops` (array): fill_type=gradient: color stops, each {red,green,blue (0-255), location (0-100 along the ramp), midpoint (5-95, default 50)}. At least 2 when supplied; sorted by location. Default: black at 0 → white…

Output parameters:

- `angle` (number)
- `color` (object)
- `context` (object)
- `created` (boolean)
- `fill_type` (string)
- `gradient_type` (string)
- `hoisted` (boolean): True when the new layer had to be moved back out of the previously-active group to honor into_active_group:false (the default). False when it landed correctly on its own, or when the move-back itself…
- `layer_name` (string)
- `parent_path` (array|null): The containing-group name chain (outermost first), empty array at the document root.
- `reverse` (boolean)
- `scale` (number)
- `stop_count` (number)

### `ps_select_layer` (~121 tokens)

Make a layer active by name. Recurses into groups; if a name appears more than once, picks the first match in stack order (top-to-bottom). Throws if no layer by that name exists. Foundational for multi-layer workflows — use after ps_duplicate_layer or ps_add_adjustment_layer when you need to focus a specific layer before applying further operations.

Input parameters:

- `name` (string, required): Name of the layer to make active. Recurses into groups; matches the first layer in stack order (top-to-bottom). Throws if no layer by that name exists.

Output parameters:

- `context` (object)
- `kind` (string)
- `name` (string)
- `selected` (boolean)

### `ps_group` (~621 tokens)

Layer group (LayerSet) lifecycle and membership — choose the operation with `op`. create/delete/ungroup/add_layer/set_blend_mode. See the `op` enum for per-operation params. delete and ungroup are DESTRUCTIVE and require confirm:true — delete removes the group AND everything inside it; ungroup dissolves the group but promotes its contents to the parent level (use ungroup, not delete, to keep the layers).

Input parameters:

- `blend_mode` (string): Blend mode (Photoshop ExtendScript BlendMode enum). PASSTHROUGH (default for new groups) lets adjustments inside the group affect the layers below the group; NORMAL treats the group as a single compo…
- `confirm` (boolean): REQUIRED for op=delete and op=ungroup, ignored by the other ops. Must be true — guards against accidental loss of a group and (for delete) everything it contains.
- `group_name` (string): Name of the destination group (recursive search).
- `into_active_group` (boolean): Photoshop's Mk-layerSection descriptor carries no placement target, so with a GROUP active it would natively nest the new group INSIDE that group. Default false hoists the new group back out so it la…
- `layer_name` (string): Name of the layer to move (recursive search). A layer is preferred over a group of the same name; a group is moved only when no layer matches, which is how one group is nested inside another.
- `layers` (array): Optional list of existing layer names to move into the new group. The first listed name ends up on top of the group stack. Layers not found are returned in `not_found`.
- `name` (string): Group name. create: name for the NEW group. delete/ungroup/set_blend_mode: the EXISTING group to act on (recursive search).
- `op` (string, required): create: make a new group above the active layer named `name` (hoisted out of an active group by default; into_active_group:true keeps Photoshop's native nesting), optionally moving `layers` into it.…

Output parameters:

- `blendMode` (string): op=set_blend_mode: the mode applied.
- `child_names` (array): op=ungroup: names of the promoted children.
- `children_promoted` (number): op=ungroup: children promoted to the parent level.
- `context` (object)
- `created` (boolean): op=create: true on success.
- `deleted` (boolean): op=delete: true on success.
- `descendants_deleted` (number): op=delete: total layers removed with the group.
- `groupName` (string)
- `hoisted` (boolean): op=create: true when the new group had to be moved back out of the previously-active group to honor into_active_group:false.
- `layerName` (string): op=add_layer: the moved layer.
- `moved` (boolean): op=add_layer: true on success.
- `moved_count` (number): op=create: layers moved into it.
- `not_found` (array): op=create: requested layer names that were not found.
- `parent_path` (array|null): op=create: the containing-group name chain (outermost first), empty array at the document root.
- `set` (boolean): op=set_blend_mode: true on success.
- `ungrouped` (boolean): op=ungroup: true on success.

### `ps_clipping_mask` (~243 tokens)

Clip or un-clip the active layer against the layer directly below it — choose with `op`. `create`: use the layer below as the alpha source; PS paints the active layer only where the layer below has pixels. Non-destructive — the upper layer is unchanged. Common for constraining a texture/photo to a shape, or masking an effect to a single underlying layer (the add_adjustment_layer tool already accepts clip_to_below for the adjustment-layer-specific case). Equivalent to Layer > Create Clipping Mask (Ctrl+Alt+G). `release`: the inverse — the layer returns to compositing against the whole canvas. Both ops are idempotent: create no-ops (already_clipped:true) on an already-clipped layer; release no-ops (released:false) on a non-clipped layer.

Input parameters:

- `op` (string, required): create: clip the active layer to the layer directly below it (that layer becomes the alpha source); no-ops (already_clipped:true) when the layer is already clipped. release: release the active layer…

Output parameters:

- `already_clipped` (boolean)
- `clipped` (boolean)
- `context` (object)
- `layerName` (string)
- `released` (boolean)

### `ps_resize_image` (~124 tokens)

Resize the entire document canvas (all layers) to the specified absolute dimensions. Destructive: downscaling permanently loses pixel data. Idempotent: same width/height always yield the same result. For aspect-preserving downscale during export, see ps_export (format=jpeg / png) which resize a duplicate. Returns updated document context.

Input parameters:

- `height` (integer, required): New height in pixels (1..300,000 — Photoshop's max canvas size).
- `width` (integer, required): New width in pixels (1..300,000 — Photoshop's max canvas size).

Output parameters:

- `context` (object)
- `height` (number)
- `success` (boolean)
- `width` (number)

### `ps_crop_document` (~257 tokens)

Crop the document to a region — EITHER anchor-relational `placement` (preferred: a region relation like inside/gap → the crop is the resolved, gate-verified region bbox, no pixel-guessing) OR absolute pixel bounds (left/top/right/bottom in document space). Destructive: pixels outside the bounds are permanently lost. Idempotent for the same bounds. Returns updated document context.

Input parameters:

- `bottom` (integer): Bottom edge position in pixels (raw mode; ignored when placement is set).
- `left` (integer): Left edge position in pixels (raw mode; ignored when placement is set).
- `placement` (object): ANCHOR-RELATIONAL crop (preferred over guessing pixels): a REGION relation (inside/gap) → the crop is the resolved region bounding box, verified by the gate. Crops ONLY if the gate PASSES. When set,…
- `right` (integer): Right edge position in pixels (raw mode; ignored when placement is set).
- `top` (integer): Top edge position in pixels (raw mode; ignored when placement is set).

Output parameters:

- `context` (object)
- `cropped` (boolean)
- `newHeight` (number)
- `newWidth` (number)
- `placement` (object): Present when anchor-relational placement was used: the resolved region + gate verdict.

### `ps_convert_image_mode` (~231 tokens)

Convert the document color mode (grayscale / rgb / cmyk / lab). Destructive and document-wide: the image is FLATTENED and, for grayscale, color is discarded (the confirmation prompt is auto-accepted). Use grayscale as the base for halftone / line-art workflows, or rgb to bring a CMYK/Lab doc back for normal editing. Returns updated document context.

Input parameters:

- `angle` (number): bitmap only: halftone screen angle in degrees (-180 to 180). PS default 45.
- `frequency` (number): bitmap only: halftone screen frequency in lines/inch (1-999). PS default 53.
- `mode` (string, required): Target document color mode. grayscale discards color (the "Discard color information?" prompt is auto-confirmed); the document is FLATTENED as part of the conversion. `bitmap` produces a 1-bit halfto…
- `shape` (string): bitmap only: halftone dot shape.

Output parameters:

- `context` (object)
- `converted` (boolean)
- `mode_after` (string)
- `mode_before` (string)
- `requested_mode` (string)

### `ps_place_image` (~272 tokens)

Place an image file (JPEG, PNG, PSD, etc.) as a new Smart Object layer in the active document, optionally offset from center. Rasterize separately if you need to apply pixel-only operations. Open-world: reads from the filesystem. Returns the new layer name, bounds, and updated document context.

Input parameters:

- `file_path` (string, required): Full path to the image file (JPEG, PNG, PSD, etc.)
- `height_percent` (number): Scale the placed layer vertically to this percent of its native height. Omit (or pass 100) to keep native size. Pair with width_percent for uniform scale (set both to the same value).
- `width_percent` (number): Scale the placed layer horizontally to this percent of its native width. Omit (or pass 100) to keep native size. Common ratios: 50 for half-size, 200 for double. Independent from height_percent — pas…
- `x` (integer): X position offset in pixels from the canvas centre (default 0). Negative places the layer further left; bounded at ±300,000 px.
- `y` (integer): Y position offset in pixels from the canvas centre (default 0). Negative places the layer further up; bounded at ±300,000 px.

Output parameters:

- `context` (object)
- `filePath` (string)
- `layerBounds` (object)
- `layerName` (string)
- `placed` (boolean)
- `position` (object)

### `ps_convert_to_smart_object` (~277 tokens)

Convert the active layer to a Smart Object, or (mode=new_via_copy) copy an existing Smart Object to an independent new one. `convert` (default) wraps the layer content so every subsequent filter becomes a Smart Filter — fully editable and non-destructive. PREREQUISITE for Camera Raw Filter, non-destructive frequency separation, and any workflow where filter parameters need to stay adjustable after the fact. Works on pixel, text, shape, and adjustment layers. Auto-promotes the background layer if needed. Wrapping an already-Smart-Object layer creates a nested Smart Object (valid in Photoshop — the inner SO is preserved as-is). `new_via_copy` requires the active layer to already be a Smart Object and yields a copy with its OWN source (unlinked). Use ps_rasterize_layer to go the other direction.

Input parameters:

- `mode` (string): convert (default): wrap the active layer into a Smart Object in place. new_via_copy: the active layer must ALREADY be a Smart Object — make a NEW Smart Object that is an INDEPENDENT copy (its own emb…

Output parameters:

- `background_promoted` (boolean)
- `context` (object)
- `is_smart_object` (boolean)
- `layer_name` (string)
- `original_kind` (string)
- `source_unlinked` (boolean)
- `was_already_smart_object` (boolean)

### `ps_rasterize_layer` (~58 tokens)

Rasterize the active layer (convert text or smart object to plain pixels). Destructive — the text/smart-object source is lost. No-op if already a normal raster layer. Returns context so the caller sees the layer kind transition.

Output parameters:

- `context` (object)
- `kind` (string)
- `message` (string)
- `newKind` (string)
- `originalKind` (string)
- `rasterized` (boolean)

### `ps_set_layer` (~366 tokens)

Set a property of the active layer — chosen via `property`. Idempotent absolute setters; do not change which layer is active. `opacity`: pass opacity (whole layer incl. styles) and/or fill_percent (pixels only — Photoshop's separate "Fill" slider, for Hard Mix / stroke-only effects). `blend_mode`: how the layer composites below (NORMAL to reset). `visibility`: show/hide via `visible`. `locked`: allLocked via `locked`. `name`: rename via `name`. Returns context so the LLM keeps state awareness.

Input parameters:

- `blend_mode` (string): Blend mode name (Photoshop ExtendScript BlendMode enum). Use COLORBLEND for the "Color" mode — Photoshop reserves the bare "COLOR" name for the SolidColor class.
- `fill_percent` (number): Fill opacity (0-100) — the "Fill" slider. Affects the layer's pixels/fill but NOT its layer styles. Distinct from opacity; used for Hard Mix and stroke-only tricks. Pass opacity and/or fill_percent.
- `locked` (boolean): Whether the layer should be fully locked (allLocked).
- `name` (string): New name for the active layer.
- `opacity` (number): Layer opacity (0-100) — affects the whole layer including its styles.
- `property` (string, required): Which property to set on the active layer (idempotent absolute setters; do not change which layer is active). opacity: opacity (whole layer incl. styles) and/or fill_percent (pixels only — the Fill s…
- `visible` (boolean): Whether the layer should be visible.

Output parameters:

- `context` (object)
- `fill_opacity` (number)
- `fill_opacity_verified` (boolean)
- `layerName` (string)
- `locked` (boolean)
- `name` (string)
- `newName` (string)
- `oldName` (string)
- `opacity` (number)
- `opacity_verified` (boolean|null)
- `property` (string)
- `requested` (number|string|boolean)
- `requested_fill_opacity` (number)
- `requested_opacity` (number|null)
- `value` (number|string)
- `verification_unreadable` (boolean): visibility only: true when the write itself did not throw but the own-flag verification read failed (Action Manager error, or the layer had no readable id) — verified is false, but this is NOT proof…
- `verified` (boolean)
- `visible` (boolean)

### `ps_duplicate_layer` (~66 tokens)

Duplicate the active layer. The new layer becomes active. Returns context so the caller sees the new active layer. Not idempotent (each call creates another copy).

Input parameters:

- `new_name` (string): Optional name for the duplicated layer. If omitted, Photoshop assigns "<name> copy".

Output parameters:

- `context` (object)
- `newName` (string)
- `originalName` (string)
- `parent_path` (array|null): The containing-group name chain (outermost first), empty array at the document root. layer.duplicate() is parent-preserving by DOM semantics, so this always matches the original layer's placement.

### `ps_copy_to_new_layer` (~233 tokens)

Copy the current selection into a NEW layer above the active one — Photoshop's "Layer via Copy" (Ctrl+J) — hoisted out of the active layer's group by default even though the underlying CpTL event carries no placement target and would otherwise nest the new layer INSIDE that group (pass into_active_group:true to keep that native nesting). The source layer is left untouched and the new copied layer becomes active. With an active selection only the selected pixels are lifted; with no selection it copies the whole active layer (a plain duplicate). Reach for this to isolate a region for independent transforms or filters (stretch, light rays, a local grade) without altering the source. Returns context so the caller sees the new active layer.

Input parameters:

- `into_active_group` (boolean): Photoshop's CpTL (Layer via Copy) event carries no placement target, so with a GROUP active it would natively nest the new layer INSIDE that group. Default false hoists the new layer back out so it l…

Output parameters:

- `context` (object)
- `copied_to_new_layer` (boolean)
- `hoisted` (boolean): True when the new layer had to be moved back out of the previously-active group to honor into_active_group:false (the default). False when it landed correctly on its own, or when the move-back itself…
- `layer_count_after` (number)
- `layer_count_before` (number)
- `new_layer_name` (string)
- `original_active_layer_name` (string)
- `parent_path` (array|null): The containing-group name chain (outermost first), empty array at the document root.

### `ps_merge` (~194 tokens)

Merge layers — choose with `mode`. `visible`: collapse all visible layers into one (DESTRUCTIVE; identities lost). `stamp`: merge visible into a NEW layer on top, leaving originals intact (Ctrl+Alt+Shift+E — the non-destructive "final tweak" composite for output sharpening/grain/contrast; prefer this when building on top rather than collapsing). `flatten`: flatten ALL layers into the background (DESTRUCTIVE; transparency filled with bg color — use sparingly, usually prefer `visible` or exporting a flattened copy). Returns context.

Input parameters:

- `mode` (string, required): visible: collapse all visible layers into one (DESTRUCTIVE; identities lost). stamp: merge visible into a NEW layer on top, originals kept (Ctrl+Alt+Shift+E — non-destructive "final tweak" composite)…

Output parameters:

- `context` (object)
- `flattened` (boolean)
- `layer_count_after` (number)
- `layer_count_before` (number)
- `merged` (boolean)
- `new_layer_name` (string)
- `original_active_layer_name` (string)
- `stamped` (boolean)

### `ps_bake_layer` (~170 tokens)

Flatten the active layer's CURRENT APPEARANCE — the layer plus any adjustment layers clipped to it plus its layer styles — into a NEW pixel layer named "<name> (baked)". Non-destructive: the originals are left intact. This is how you get real baked pixels out of a non-destructive stack: clip a Hue/Saturation (saturation -100) or an Invert adjustment to a layer, then bake to get a desaturated / inverted PIXEL layer for techniques that need actual pixels (line art, blurred-layer blends). Also works on a lone layer with nothing clipped to it — it rasterizes that layer's own appearance (layer styles, smart-object or text content) into a flat pixel copy. The active layer must be top-level (not inside a group).

Output parameters:

- `baked` (boolean)
- `baked_layer_name` (string)
- `clipped_layers_baked` (number)
- `context` (object)
- `source_layer_name` (string)

### `ps_add_layer_style` (~448 tokens)

Apply a layer style (drop shadow, stroke, outer glow, inner shadow, inner glow, or color overlay) to the active layer. Non-destructive and editable. For PHOTO workflows: `stroke` = print-style border around the image (apply to the flattened photo on a transparent canvas, or to a duplicated background); `outer_glow` = atmospheric lift on highlights (halo around the sun, glow around a window or lamp); `drop_shadow` = depth on text overlays and layered composites. Drop shadow uses Multiply blend; outer glow uses Screen; stroke uses Normal. Cannot be applied to a background layer (duplicate or convert it first). Returns context — applying a style changes what exists on the layer (the Lefx descriptor).

Input parameters:

- `angle` (number): drop_shadow/inner_shadow: light angle in degrees. 90 = top-down (standard product shadow).
- `color` (object): Effect color RGB (0-255). Default black for drop shadow, white for glow, black for stroke.
- `distance` (number): drop_shadow/inner_shadow: shadow offset in pixels.
- `glow_size` (number): outer_glow/inner_glow: glow blur size in pixels.
- `glow_spread` (number): outer_glow/inner_glow: glow choke/spread (0-100%).
- `opacity` (number): Effect opacity (0-100).
- `size` (number): drop_shadow/inner_shadow: shadow blur size in pixels.
- `spread` (number): drop_shadow/inner_shadow: shadow choke/spread (0-100%).
- `stroke_position` (string): stroke only: where the stroke sits relative to the layer edge.
- `stroke_size` (number): stroke only: stroke width in pixels.
- `style` (string, required): Which layer style to apply. drop_shadow/inner_shadow share angle/distance/spread/size; outer_glow/inner_glow share glow_size/glow_spread; color_overlay uses only color + opacity. inner_shadow = reces…

Output parameters:

- `applied` (boolean)
- `context` (object)
- `layerName` (string)
- `style` (string)

### `ps_transform_layer` (~1106 tokens)

Transform the active layer — choose the operation with `op`. `fit` scales to fit (letterbox) or fill (crop) the canvas and centers (idempotent). `scale` does uniform (scale_percent) or non-uniform stretch/squash (scale_x_percent/scale_y_percent) — multiplicative, not idempotent. `move` translates via exactly one of delta (relative), absolute (top-left target), center_on (center target — best for "place inside the frame opening"), or an anchor-relational `placement` (preferred: a point relation → the layer center moves to the resolved, gate-verified point); mixing the raw modes errors. `rotate` rotates by relative degrees around center. `flip` mirrors horizontal/vertical. `skew` slants the layer (skew_h_degrees/skew_v_degrees). `free` is a numeric free-transform (scale + degrees + offset). scale/move/rotate/flip/skew/free auto-promote the background layer (background_promoted=true).

Input parameters:

- `absolute_x` (number): ABSOLUTE mode: target X for the layer's bounds top-left corner, in document pixels. Pair with absolute_y. Use when you know exactly where the top-left should land. Mutually exclusive with delta_* / c…
- `absolute_y` (number): ABSOLUTE mode: target Y for the layer's bounds top-left corner, in document pixels. Pair with absolute_x.
- `axis` (string): 'horizontal' mirrors left-right; 'vertical' mirrors top-bottom.
- `center_anchor` (boolean): Scale from center (true) or top-left (false). Default: true.
- `center_on_x` (number): CENTER mode: target X for the layer's bounds CENTER point, in document pixels. Pair with center_on_y. Use when placing a layer inside a known region (e.g. a frame opening). Mutually exclusive with de…
- `center_on_y` (number): CENTER mode: target Y for the layer's bounds CENTER point, in document pixels. Pair with center_on_x.
- `degrees` (number): Rotation angle in degrees (positive = clockwise, negative = counter-clockwise).
- `delta_x` (number): RELATIVE mode: horizontal pixel offset from the layer's current position. Pair with delta_y. Mutually exclusive with absolute_*/center_on_*.
- `delta_y` (number): RELATIVE mode: vertical pixel offset from the layer's current position. Pair with delta_x.
- `mode` (string): `fit` (default) scales the layer to fit inside the canvas while preserving aspect — letterboxes on the short edge. `fill` covers the entire canvas — crops on the long edge. Both preserve aspect ratio…
- `offset_x` (number): op=skew/free: horizontal translation in pixels (default 0).
- `offset_y` (number): op=skew/free: vertical translation in pixels (default 0).
- `op` (string, required): Which transform to apply to the active layer. fit: scale to fit/fill the canvas + center (mode fit|fill). scale: uniform scale_percent OR non-uniform scale_x_percent/scale_y_percent (center_anchor).…
- `placement` (object): ANCHOR-RELATIONAL move (preferred over guessing a pixel): a POINT relation (centroid/midpoint/offset) → the layer's CENTER is moved to the resolved, gate-verified point (e.g. "center this layer on th…
- `scale_percent` (number): Uniform scale percentage (e.g. 50 = 50%, 200 = 200%). Use for proportional scaling.
- `scale_x_percent` (number): Non-uniform: horizontal scale percentage. Pair with scale_y_percent to stretch/squash (the #1 pixel-stretch effect). If only one axis is given the other defaults to 100%.
- `scale_y_percent` (number): Non-uniform: vertical scale percentage. Pair with scale_x_percent.
- `skew_h_degrees` (number): op=skew: horizontal skew (slant) angle in degrees — positive slants the top edge right. At least one of skew_h_degrees / skew_v_degrees is required for op=skew.
- `skew_v_degrees` (number): op=skew: vertical skew (slant) angle in degrees — positive slants the left edge down.

Output parameters:

- `applied_delta_x` (number)
- `applied_delta_y` (number)
- `axis` (string)
- `background_promoted` (boolean)
- `context` (object)
- `degrees` (number)
- `fitted` (boolean)
- `flipped` (boolean)
- `mode` (string)
- `moved` (boolean)
- `newSize` (object)
- `new_bounds` (object)
- `originalSize` (object)
- `percent` (number)
- `placement` (object): Present when op=move used anchor-relational placement: the resolved point + gate verdict.
- `rotate_degrees` (number)
- `rotated` (boolean)
- `scaleFactor` (number)
- `scalePercent` (number)
- `scale_x_percent` (number)
- `scale_y_percent` (number)
- `scaled` (boolean)
- `skew_h_degrees` (number)
- `skew_v_degrees` (number)
- `transformed` (boolean)

### `ps_filter` (~3493 tokens)

Apply a Photoshop filter (op=apply, the default) to a DUPLICATE of the active layer by default — the original is preserved, undo by deleting the copy. Pass apply_to_active_layer:true to bake into the original instead. Choose the filter with `type` (see the `type` field for its params); pass as_smart_filter:true on a Smart Object to apply it as a re-editable SMART FILTER instead of rasterizing. This same tool also reads and manages that re-editable Smart Filter stack: op=list (every filter's index/name/type/enabled/opacity/blend), op=set_visibility (toggle one off/on), op=set_blend (restyle opacity/blend_mode), op=remove (delete one). Management ops need a 1-based `index` from op=list first — index 1 is the first-applied filter, at the bottom of the stack. Covers blur, sharpen, noise, high_pass, pixelate, distort, displace, and oil_paint.

Input parameters:

- `amount` (number): Filter strength. Range depends on type — sharpen 1–500, noise 0.1–400, radial_blur 1–100, distort/ripple −999–999.
- `amplitude_max` (integer): wave only: maximum amplitude (1-999).
- `amplitude_min` (integer): wave only: minimum amplitude (1-998; must be <= amplitude_max).
- `angle` (number): Angle in degrees. Used by motion_blur (−360–360) and distort/twirl (−999–999).
- `angle_1` (integer): color_halftone only: screen angle for channel 1 in degrees. PS default 108.
- `angle_2` (integer): color_halftone only: screen angle for channel 2. PS default 162.
- `angle_3` (integer): color_halftone only: screen angle for channel 3. PS default 90.
- `angle_4` (integer): color_halftone only: screen angle for channel 4. PS default 45.
- `apply_to_active_layer` (boolean): If false (default), the filter is applied to a duplicate of the active layer named "<OpName> (<Original Name>)" — the original is preserved and the LLM can undo simply by deleting the copy. If true,…
- `as_smart_filter` (boolean): If true, apply the filter as a re-editable SMART FILTER riding the Smart Object instead of baking it into pixels — nothing is rasterized, and the filter can later be toggled, re-blended or removed in…
- `blend_mode` (string): set_blend only: how the filter result composites against the unfiltered layer. Same names as ps_set_layer. Omit to leave the current mode untouched.
- `blue_preserve_details` (number): Per-channel: blue channel preserve-details percentage.
- `blue_strength` (number): Per-channel: blue channel noise-reduction strength. Usually the noisiest channel in low-light photos.
- `bristle_detail` (number): Bristle detail (0-10).
- `brush_scale` (number): Brush scale (0.1-2).
- `cell_size` (integer): Cell size in pixels — used by mosaic (2-300, PS default 10), crystallize (3-300), and pointillize (3-300, PS default 5). Ignored by color_halftone/facet/fragment.
- `center_placement` (object): Grounded alternative to center_x/center_y: NAME the blur center (a `placement` resolving to a POINT — an object centroid, an extremum, a grid intersection). The resolved document-pixel point is norma…
- `center_x` (number): Horizontal blur center, normalized 0-1 (0.5 = middle). Resolution-independent.
- `center_y` (number): Vertical blur center, normalized 0-1 (0.5 = middle). Resolution-independent.
- `cleanliness` (number): Stroke cleanliness / smoothness (0-10).
- `color_noise` (number): Color (chroma) noise reduction (0-100). PS default 45. Hits the colorful speckle noise typical of high-ISO photos.
- `conversion` (string): polar only: rect_to_polar wraps the image into a circle; polar_to_rect unwraps it.
- `depth_source` (string): Depth map source for selective focus. "none" = uniform blur across the whole layer. "transparency" = use the layer alpha channel as depth (foreground sharper). "layerMask" = use the layer mask. PS de…
- `displacement_map` (string): How the map fits the layer: stretch_to_fit (resize the map) or tile (repeat it).
- `distribution` (string): Noise distribution type. Default: UNIFORM.
- `edge` (string): trace_contour only: trace the lower or upper edge of the level. PS default lower.
- `enabled` (boolean): set_visibility only: true shows the filter, false hides it. The filter stays in the stack either way and keeps all its settings.
- `fiber_strength` (integer): fibers only: fiber strength / definition (1-64). PS default 4.
- `focal_distance` (number): Focal-plane depth value (0-255), only meaningful when depth_source != none. Pixels at this depth stay sharp; pixels farther from it blur progressively.
- `generators` (integer): wave only: number of wave generators (1-999).
- `green_preserve_details` (number): Per-channel: green channel preserve-details percentage.
- `green_strength` (number): Per-channel: green channel noise-reduction strength.
- `height` (integer): emboss only: relief height in pixels (1-100). PS default 3.
- `highlight_fade` (number): Highlights tab: amount of sharpening to fade in highlight regions (0-100). PS default 0.
- `highlight_radius` (number): Highlights tab: local-contrast radius in pixels (1-100). PS default 30.
- `highlight_tonal_width` (number): Highlights tab: tonal width (0-100). PS default 50.
- `horizontal` (integer): offset only: horizontal shift in pixels (positive = right).
- `horizontal_scale` (integer): Horizontal displacement scale (-999 to 999). PS default 10.
- `index` (integer): 1-based index of the filter to act on, as reported by op=list. 1 is the FIRST-APPLIED filter (bottom of the Smart Filters stack in the Layers panel). Required for every op except 'list'.
- `invert_depth` (boolean): Invert the depth map. PS default false.
- `iris_blade_curvature` (number): Iris blade curvature (0-100). 0 = polygonal bokeh, 100 = perfectly circular. PS default 0.
- `iris_rotation` (number): Iris rotation in degrees (0-360). Rotates the iris-shape pattern. PS default 0.
- `iris_shape` (string): Aperture iris shape — affects the look of out-of-focus highlights (bokeh). PS default hexagon. Triangle = 3 blades, octagon = 8 blades. Real lenses with fewer blades produce more polygonal bokeh.
- `level` (integer): trace_contour only: brightness level the contour traces (0-255). PS default 128.
- `light_direction` (integer): Lighting angle in degrees (-180 to 180).
- `lighting_on` (boolean): Whether the lighting/shine relief is applied.
- `map_path` (string): Absolute path to the displacement-map .psd file (required). The map's brightness drives the per-pixel warp — mid-gray = no shift, lighter/darker push in opposite directions.
- `max_radius` (integer): color_halftone only: maximum dot radius in pixels (4-127). PS default 8.
- `method` (string): spin = rotational blur around the center (turntable motion); zoom = radial streaks toward/from the center (the classic "god rays" / speed-zoom look).
- `mode` (string): surface_blur = blur while preserving edges above a threshold (skin-smoothing; radius + threshold); box_blur = fast square-kernel blur (radius); average = fill the layer with its single average color…
- `monochromatic` (boolean): Apply monochromatic noise. Default: false.
- `motion_angle` (number): Motion blur angle in degrees (-360 to 360). Only meaningful when remove_mode=motionBlur.
- `noise_amount` (number): Noise added to the blurred result (0-100). PS default 0. Lens Blur can produce un-naturally clean blur regions; a small noise amount (5-15) keeps the texture believable.
- `noise_distribution` (string): Noise distribution type. PS default uniform.
- `noise_monochromatic` (boolean): Monochromatic noise (luminance-only). PS default true.
- `noise_reduction` (number): Noise reduction during sharpening (0-100). PS default 10. Prevents sharpening from amplifying existing noise. For low-light photos, raise this (25-50).
- `number` (integer): tiles only: number of tiles across (1-99). PS default 10.
- `offset` (integer): tiles only: maximum tile offset percent (1-99). PS default 10.
- `op` (string): apply (default): apply a NEW filter — set `type` (+ its own params). list: read every re-editable Smart Filter on the active Smart Object (index, name, type, enabled, opacity, blend mode). set_visibi…
- `opacity` (number): set_blend only: filter opacity 0-100. Omit to leave the current opacity untouched.
- `per_channel` (boolean): Enable per-channel advanced mode. If true, the per-channel strength/preserve_details params (red_*, green_*, blue_*) override the global strength/preserve_details for each RGB channel — useful when n…
- `preserve` (string): maximum/minimum only: edge-preservation shape. PS default roundness.
- `preserve_details` (number): Preserve details percentage (0-100). PS default 50. Higher protects edges; lower lets the smoother kick in further.
- `quality` (string): Render quality. best is smoothest but slowest.
- `radius` (number): Radius/distance in px. Range depends on type — gaussian_blur 0.1–250, motion_blur 1–999, lens_blur 0–100, smart_sharpen 0.1–64, high_pass 0.1–1000.
- `random_seed` (integer): wave only: random seed for the wave pattern (change for a different pattern).
- `red_preserve_details` (number): Per-channel: red channel preserve-details percentage (0-100). Only used when per_channel=true.
- `red_strength` (number): Per-channel: red channel noise-reduction strength (0-10). Only used when per_channel=true.
- `remove_jpeg_artifact` (boolean): Remove JPEG compression artifacts (the 8x8 block boundaries and ringing). PS default false.
- `remove_mode` (string): Blur model to remove. gaussianBlur (default) is the general-purpose modern Unsharp Mask replacement. lensBlur removes lens-style softness with better edge handling. motionBlur removes directional mot…
- `ridges` (integer): zigzag only: number of concentric ridges (0-20). PS default 5.
- `scale_horizontal` (integer): wave only: horizontal scale percent (1-100).
- `scale_vertical` (integer): wave only: vertical scale percent (1-100).
- `seed` (integer): fibers only: randomize seed — change for a different fiber pattern. PS default 12345.
- `shadow_fade` (number): Shadows tab: amount of sharpening to fade in shadow regions (0-100). 0 = sharpen shadows fully, 100 = no shadow sharpening. Useful for preventing shadow-noise amplification. PS default 0.
- `shadow_radius` (number): Shadows tab: local-contrast radius in pixels (1-100). PS default 30. Defines the neighborhood used to classify pixels as shadows.
- `shadow_tonal_width` (number): Shadows tab: tonal width — how broadly "shadows" is defined (0-100). PS default 50.
- `sharpen_details` (number): Sharpening to apply after noise reduction (0-100). PS default 25. Compensates for the softening that noise reduction causes.
- `shine` (number): Specular shine (0-10).
- `size` (string): ripple only: ripple wavelength size.
- `specular_brightness` (number): Specular highlight brightness boost (0-255). PS default 0. Lift highlights to enhance bokeh "balls" — values around 50-100 produce visible specular highlights, higher = more dramatic.
- `specular_threshold` (number): Specular highlight threshold (0-255). PS default 255 (no specular boost applies). Lower the threshold to let more pixels be treated as specular highlights for the brightness boost. Typical photograph…
- `strength` (number): Luminance noise reduction strength (0-10). PS default 5. Higher = more aggressive noise reduction but more detail loss.
- `stylization` (number): Brush-stroke stylization (0.1-10).
- `threshold` (integer): surface_blur only: tonal threshold (0-255) — edges differing by more than this are preserved. PS default 20.
- `type` (string): Which filter to apply. Required when op=apply (the default); ignored otherwise. Each type uses its own parameters: gaussian_blur(radius); motion_blur(angle, radius); lens_blur(radius, iris_shape, …);…
- `undefined_areas` (string): How to fill areas pushed outside the layer.
- `variance` (integer): fibers only: color variance / streak length (1-64). PS default 16.
- `vertical` (integer): offset only: vertical shift in pixels (positive = down).
- `vertical_scale` (integer): Vertical displacement scale (-999 to 999). PS default 10.
- `wave_type` (string): wave only: waveform shape.
- `wavelength_max` (integer): wave only: maximum wavelength (1-999).
- `wavelength_min` (integer): wave only: minimum wavelength (1-998; must be <= wavelength_max).
- `wind_direction` (string): wind only: streak direction. PS default left.
- `wind_method` (string): wind only: streak intensity/style. PS default wind.

Output parameters:

- `applied` (boolean)
- `blend_mode` (string)
- `context` (object)
- `count` (number)
- `enabled` (boolean)
- `filter` (string)
- `filter_name` (string)
- `filter_type` (string)
- `filters` (array)
- `index` (number)
- `is_smart_object` (boolean)
- `layer_name` (string)
- `opacity` (number)
- `original_layer_name` (string)
- `remaining_count` (number)
- `removed` (boolean)
- `removed_filter_name` (string)
- `removed_filter_type` (string)
- `requested_enabled` (boolean)
- `target_layer_name` (string)
- `target_was_copy` (boolean)
- `visibility_set` (boolean)

### `ps_apply_adjustment` (~737 tokens)

Apply a DESTRUCTIVE tonal adjustment that Photoshop does NOT offer as an adjustment layer — chosen via `type`. Runs on a DUPLICATE of the active layer by default (auto-duplicate-first — the original is preserved; revert by deleting the copy); pass `apply_to_active_layer: true` to bake in place. Auto-rasterizes text/smart-object layers. `shadows_highlights` recovers blown highlights + crushed shadows in one pass (defaults match Adobe's dialog: 35 shadow amount, +20 color correction); `equalize` stretches/flattens the histogram (parameter-free); `color_lookup` bakes a 3DLUT grade (cl_lut_name required — leaf name of a file in Presets/3DLUTs/ or an absolute .cube/.3dl/.look path). For EDITABLE tonal/color work, prefer ps_add_adjustment_layer.

Input parameters:

- `apply_to_active_layer` (boolean): If false (default), the color lookup is applied to a duplicate of the active layer named "<OpName> (<Original Name>)" — the original is preserved and the LLM can undo simply by deleting the copy. If…
- `black_clip` (number): Percent of the darkest shadow pixels to clip to pure black (0-50). PS default 0.01 — minimal clipping. Higher values increase contrast but lose shadow detail.
- `cl_lut_name` (string): Leaf name of a 3DLUT file in PS's Presets/3DLUTs/ folder (e.g. "TealOrangePlusContrast.3DL", "FallColors.look", "Kodak 5205 Fuji 3510 (by Adobe).cube") OR an absolute path to a .3DL / .look / .cube f…
- `color_correction` (number): Color saturation compensation for recovered shadows (-100 to +100). PS default +20 — counteracts the desaturation that shadow recovery tends to produce.
- `highlight_amount` (number): Highlight recovery amount (0-100). PS default 0.
- `highlight_radius` (number): Local-contrast radius for highlight recovery in pixels (0-2500). PS default 30.
- `highlight_width` (number): Tonal width of highlights (0-100). PS default 50.
- `midtone_contrast` (number): Midtone contrast (-100 to +100). PS default 0.
- `shadow_amount` (number): Shadow recovery amount (0-100). PS default 35.
- `shadow_radius` (number): Local-contrast radius for shadow recovery in pixels (0-2500). PS default 30.
- `shadow_width` (number): Tonal width of shadows (0-100). Wider = more midtones treated as shadow. PS default 50.
- `type` (string, required): Which destructive adjustment to bake (none exist as adjustment layers in PS). shadows_highlights: one-pass shadow/highlight recovery (shadow_amount, highlight_amount, …). equalize: parameter-free his…
- `white_clip` (number): Percent of the brightest highlight pixels to clip to pure white (0-50). PS default 0.01. Higher values increase contrast but lose highlight detail.

Output parameters:

- `color_correction` (number)
- `context` (object)
- `filter` (string)
- `highlight_amount` (number)
- `highlight_radius` (number)
- `highlight_width` (number)
- `lut_format` (string)
- `lut_path` (string)
- `midtone_contrast` (number)
- `original_layer_name` (string)
- `shadow_amount` (number)
- `shadow_radius` (number)
- `shadow_width` (number)
- `target_layer_name` (string)
- `target_was_copy` (boolean)

### `ps_add_adjustment_layer` (~2977 tokens)

Create a non-destructive adjustment layer above the active layer — hoisted out of the active layer's group by default even though Photoshop's own Mk-AdjL placement rule would otherwise nest it INSIDE that group (pass into_active_group:true to keep that native nesting). Supports the full real-Photoshop tonal/color surface: Curves (with S-curve presets), Levels, Hue/Saturation, Brightness/Contrast, Black & White (with optional tint), Color Balance, Photo Filter (preset or custom color), Vibrance, Channel Mixer, Selective Color, Gradient Map (preset), Exposure (stops + offset + gamma), Color Lookup (3DLUT presets or custom file path), and Invert. Values are editable, maskable, and removable. This is the canonical entry point for tonal/color adjustments — EXCEPT global tone/color on raw-sourced documents, which starts with a Camera Raw develop pass when a camera-raw develop tool is registered (see ps_open_document's is_raw_source); the old destructive bake tools (auto_levels / auto_contrast / desaturate / invert) were removed on 2026-05-31 — if you genuinely need a pixel bake, follow this call with `ps_merge` (mode=visible). Optionally clips the adjustment to only affect the layer directly below it. If a selection is active at call time, the new layer is automatically masked by it (toggle with mask_from_selection / mask_inverted). For destructive ops that don't have an adjustment-layer equivalent in Photoshop (Shadows/Highlights — single-pass shadow/highlight recovery), use `ps_apply_adjustment` (type=shadows_highlights) which auto-duplicates the active layer to keep the original intact. Returns context (the new adjustment layer becomes active) plus parent_path — the actual containing-group chain, so placement is never silent.

Input parameters:

- `black_point` (number): For type=levels. Input black (0-255).
- `brightness` (number): For type=brightness_contrast. Brightness (-100 to 100).
- `bw_blues` (number): For type=black_and_white. Blue-channel mapping (-200 to 300). PS default 20.
- `bw_cyans` (number): For type=black_and_white. Cyan-channel mapping (-200 to 300). PS default 60.
- `bw_greens` (number): For type=black_and_white. Green-channel mapping (-200 to 300). PS default 40.
- `bw_magentas` (number): For type=black_and_white. Magenta-channel mapping (-200 to 300). PS default 80.
- `bw_reds` (number): For type=black_and_white. Red-channel lightness mapping (-200 to 300). PS default 40.
- `bw_tint` (boolean): For type=black_and_white. If true, applies a single-color tint over the grayscale conversion (split-toning effect). Pair with bw_tint_hue + bw_tint_saturation.
- `bw_tint_hue` (number): For type=black_and_white when bw_tint=true. Tint hue in degrees (-180 to 180). Default 220 (cool blue).
- `bw_tint_saturation` (number): For type=black_and_white when bw_tint=true. Tint saturation (0 to 100). Default 25.
- `bw_yellows` (number): For type=black_and_white. Yellow-channel mapping (-200 to 300). PS default 60.
- `cb_highlights_cyan_red` (number): For type=color_balance. Highlights: cyan↔red shift.
- `cb_highlights_magenta_green` (number): For type=color_balance. Highlights: magenta↔green shift.
- `cb_highlights_yellow_blue` (number): For type=color_balance. Highlights: yellow↔blue shift.
- `cb_midtones_cyan_red` (number): For type=color_balance. Midtones: cyan↔red shift.
- `cb_midtones_magenta_green` (number): For type=color_balance. Midtones: magenta↔green shift.
- `cb_midtones_yellow_blue` (number): For type=color_balance. Midtones: yellow↔blue shift.
- `cb_preserve_luminosity` (boolean): For type=color_balance. Preserve luminosity while shifting color. Default true (matches the PS dialog default).
- `cb_shadows_cyan_red` (number): For type=color_balance. Shadows: cyan↔red shift (-100 cyan to +100 red). Default 0.
- `cb_shadows_magenta_green` (number): For type=color_balance. Shadows: magenta↔green shift (-100 magenta to +100 green).
- `cb_shadows_yellow_blue` (number): For type=color_balance. Shadows: yellow↔blue shift (-100 yellow to +100 blue).
- `cl_lut_name` (string): For type=color_lookup. The LUT file name as Photoshop sees it. Common built-in 3DLUT presets: "3Strip.look", "Bleach Bypass.look", "Candlelight.CUBE", "Crisp_Warm.look", "Crisp_Winter.look", "DropBlu…
- `cl_lut_type` (string): For type=color_lookup. Which LUT slot to load into. Default 3dlut covers .cube / .3dl / .look files (the photographer-typical case). abstract and device_link are for color-management workflows.
- `clip_to_below` (boolean): If true, the adjustment only affects the layer directly below.
- `cm_b_constant` (number): For type=channel_mixer. Constant added to Blue output.
- `cm_b_from_b` (number): For type=channel_mixer. Blue-from-Blue weight. PS default 100.
- `cm_b_from_g` (number): For type=channel_mixer. Blue-from-Green weight.
- `cm_b_from_r` (number): For type=channel_mixer. Blue-from-Red weight.
- `cm_g_constant` (number): For type=channel_mixer. Constant added to Green output.
- `cm_g_from_b` (number): For type=channel_mixer. Green-from-Blue weight.
- `cm_g_from_g` (number): For type=channel_mixer. Green-from-Green weight. PS default 100.
- `cm_g_from_r` (number): For type=channel_mixer. Green-from-Red weight.
- `cm_gray_constant` (number): For type=channel_mixer with cm_monochrome=true. Constant added to gray output.
- `cm_gray_from_b` (number): For type=channel_mixer with cm_monochrome=true. Blue contribution to gray. PS default 20.
- `cm_gray_from_g` (number): For type=channel_mixer with cm_monochrome=true. Green contribution to gray. PS default 40.
- `cm_gray_from_r` (number): For type=channel_mixer with cm_monochrome=true. Red contribution to gray (-200 to 200). PS default 40.
- `cm_monochrome` (boolean): For type=channel_mixer. If true, output is single gray channel and only cm_gray_* params apply. If false, the per-output cm_{r,g,b}_from_* and cm_{r,g,b}_constant params apply for RGB→RGB remix.
- `cm_r_constant` (number): For type=channel_mixer. Constant added to Red output.
- `cm_r_from_b` (number): For type=channel_mixer. Red-from-Blue weight. Default 0.
- `cm_r_from_g` (number): For type=channel_mixer. Red-from-Green weight. Default 0.
- `cm_r_from_r` (number): For type=channel_mixer with cm_monochrome=false. Red-from-Red weight. PS default 100 (identity).
- `contrast` (number): For type=brightness_contrast. Contrast (-100 to 100).
- `curves_preset` (string): For type=curves only. Default sCurveMedium.
- `exp_exposure` (number): For type=exposure. Exposure shift in STOPS (-20 to +20). PS default 0. Photographer-feeling tonal control — 1 stop ≈ 2× linear brightness.
- `exp_gamma` (number): For type=exposure. Gamma correction (0.01 to 9.99). PS default 1.0 (identity). Values <1 brighten midtones; >1 darken them.
- `exp_offset` (number): For type=exposure. Offset shift (-0.5 to +0.5). PS default 0. Shifts the black point — most useful for paired with negative exposure for moody/crushed-shadow looks.
- `gamma` (number): For type=levels. Midpoint gamma.
- `gm_dither` (boolean): For type=gradient_map. Apply dithering to reduce banding.
- `gm_preset` (string): For type=gradient_map. Preset gradient. "black_to_white" is the canonical tonal B&W via gradient. "sepia" is a warm vintage tone. "tint" maps black→tint_color→white using gm_tint_color_hex. For arbit…
- `gm_reverse` (boolean): For type=gradient_map. Reverse the gradient direction.
- `gm_stops` (array): For type=gradient_map. Custom color stops overriding gm_preset — each {red,green,blue (0-255), location (0-100 shadows→highlights), midpoint (5-95, default 50)}. At least 2; sorted by location. E.g.…
- `gm_tint_color_hex` (string): For type=gradient_map with gm_preset=tint. Mid-tone tint color as a hex string like "#5588CC". Only used when gm_preset=tint.
- `hue` (number): For type=hue_saturation. Hue shift in degrees (-180 to 180).
- `into_active_group` (boolean): Photoshop's Mk-AdjL descriptor carries no placement target, so with a GROUP active it would natively nest the new layer INSIDE that group. Default false hoists the new layer back out so it lands abov…
- `lightness` (number): For type=hue_saturation. Lightness (-100 to 100).
- `mask_from_selection` (boolean): If true (default) and there is an active selection at the time of this call, the new adjustment layer is automatically masked by that selection. If false, any existing selection is dropped first and…
- `mask_inverted` (boolean): Only meaningful when mask_from_selection is true AND there is an active selection. If true, the resulting mask is inverted — so the adjustment affects EVERYTHING OUTSIDE the selection rather than ins…
- `name` (string): Optional name for the new adjustment layer.
- `pf_color_hex` (string): For type=photo_filter. Custom filter color as a hex string like "#EC8A00". Only used when pf_preset is not set.
- `pf_density` (number): For type=photo_filter. Filter strength (1-100). PS default 25.
- `pf_preserve_luminosity` (boolean): For type=photo_filter. Preserve luminosity. Default true.
- `pf_preset` (string): For type=photo_filter. Named filter preset. If set, takes precedence over pf_color_hex. Common picks: warming_85 (warm portraits), cooling_80 (cool down skies), sepia (vintage), warming_lba / cooling…
- `pos_levels` (number): For type=posterize. Number of tonal levels per channel (2-255). PS default 4. Lower values yield a more graphic / illustration look (2-4); higher values are gentler.
- `saturation` (number): For type=hue_saturation. Master saturation (-100 to 100). Note: vibrance has its own vib_saturation param.
- `sc_colors` (object): For type=selective_color. Nested per-color-family CMYK shifts. Each family is an object {cyan, magenta, yellow, black} with values -100 to 100. Omitted families default to zero. Families: reds, yello…
- `sc_method` (string): For type=selective_color. "relative" scales adjustments by the existing color amount (subtle, the PS default). "absolute" applies fixed CMYK shifts (more aggressive).
- `thr_level` (number): For type=threshold. Threshold luminance (1-255). PS default 128. Pixels brighter than the threshold become white; darker become black.
- `type` (string, required): Adjustment kind.
- `vib_saturation` (number): For type=vibrance. Master saturation override (-100 to 100). Affects all colors equally.
- `vib_vibrance` (number): For type=vibrance. Vibrance (-100 to 100). Saturation boost that protects skin tones and already-saturated colors. Gentler than hue_saturation.saturation.
- `white_point` (number): For type=levels. Input white (0-255).

Output parameters:

- `clipError` (string)
- `clipped` (boolean)
- `context` (object)
- `created` (boolean)
- `customValuesApplied` (boolean)
- `had_selection` (boolean)
- `hoisted` (boolean): True when the new layer had to be moved back out of the previously-active group to honor into_active_group:false (the default). False when it landed correctly on its own, or when the move-back itself…
- `kindMatches` (boolean)
- `layerKind` (string)
- `layerName` (string)
- `mask_applied` (boolean)
- `mask_inversion_error` (string|null)
- `mask_inverted` (boolean)
- `parent_path` (array|null): The containing-group name chain (outermost first), empty array at the document root.
- `raw_develop_pending` (string): Advisory, present only when the active document was opened from a raw source this session and no Camera Raw develop pass has run yet. Nothing failed — the layer was created. Global tone/color on raw…
- `type` (string)

### `ps_text` (~412 tokens)

Text layer — create it or style it, chosen with `op`. create: a new text layer with `text` at `x`/`y` and `font_size`. set_content/set_font/set_color/set_alignment act on the currently active text layer (throws if it isn't one). Font names accept either the PostScript name ("ArialMT") or family name ("Arial", resolved to its Regular/first variant); throws clearly if no installed font matches. The set_* ops are idempotent.

Input parameters:

- `alignment` (string): Text alignment.
- `blue` (integer): Blue component (0-255).
- `font_name` (string): Font family name (e.g., "Arial", "Helvetica").
- `font_size` (number): Font size in points, up to 1296 — Photoshop's own ceiling for the Character panel. create: initial size (default 24). set_font: new size (optional — omit to leave the current size unchanged).
- `green` (integer): Green component (0-255).
- `op` (string, required): create: new text layer with `text` at `x`/`y` (default 100,100) and `font_size` (default 24). set_content: replace the active text layer's content with `text`. set_font: set the active text layer's f…
- `red` (integer): Red component (0-255).
- `text` (string): create: initial text content. set_content: new text content, replacing the existing text.
- `x` (integer): X position in pixels (default 100). Bounded at ±300,000 px.
- `y` (integer): Y position in pixels (default 100). Bounded at ±300,000 px.

Output parameters:

- `alignment` (string): op=set_alignment: the alignment applied.
- `color` (string): op=set_color: the RGB() string applied.
- `context` (object)
- `created` (boolean): op=create: true on success.
- `font` (string): op=set_font: the font actually matched.
- `fontSize` (number): op=create: the size applied.
- `layerName` (string): op=create: the new layer name.
- `matched_by` (string): op=set_font: how `font_name` was resolved.
- `position` (object): op=create: {x, y}.
- `requested` (string): op=set_font: the font requested.
- `size` (number): op=set_font: the size applied, if given.
- `text` (string): op=create/set_content: the text content.

### `ps_select` (~1599 tokens)

Create a NEW selection — choose with `mode`. (To edit the CURRENT selection instead — including growing it by colour similarity — use ps_modify_selection.) `all` selects the canvas; `none` deselects; `inverse` inverts the current selection (e.g. select the subject, then inverse to act on the background). `rectangle` (left/top/right/bottom, optional feather_px to avoid hard block-edges in smooth sky). `ellipse` (left/top/right/bottom bounding box + anti_alias — circles/ovals). `color_range` (target red/green/blue + fuzziness — "select all the red / skin tones"). `luminance_range` (highlights/shadows/midtones — foundation for glow / dodge-burn). `magic_wand` (click x/y + tolerance, contiguous). `focus_area` selects by depth of field rather than subject or colour (+in_focus_radius, soft_mask) — check whole_canvas_selected/warning in the result before trusting it. `grow` / `similar` are DEPRECATED here (they act on the CURRENT selection, not a new one) — use ps_modify_selection(op=grow|similar) instead; kept for one release for backward compatibility, identical behaviour. rectangle/ellipse/magic_wand also accept a grounded `placement` (NAME a region/point instead of guessing pixels — resolved + gate-verified). The geometric/color/wand modes take selection_type (replace|add|subtract|intersect) to combine with an existing selection and return a rich selection_info bundle — verify it (or ps_get_selection_preview) before committing to a mask.

Input parameters:

- `anti_alias` (boolean): Soften the selection edge. Default true.
- `blue` (integer): Target blue (0-255).
- `bottom` (number): Bottom edge in pixels
- `contiguous` (boolean): If true (default), only selects connected matching pixels.
- `feather_px` (number): Feather the selection edge by this many pixels after creating it. Default 0 (hard edge). REQUIRED for regional adjustments in smooth areas like open sky — a hard rectangular selection will produce a…
- `fuzziness` (integer): skin_tones: tolerance/spread around skin-tone colours (0-200). Default 40.
- `green` (integer): Target green (0-255).
- `in_focus_radius` (number): How much blur still counts as "in focus", in pixels. Higher pulls more of the soft transition zone into the selection; lower keeps only the crisply resolved plane. 4.07 is the Photoshop dialog defaul…
- `left` (number): Left edge in pixels
- `lower_limit` (integer): highlights/midtones: lower brightness bound (0-255). Default 190 (highlights) / 105 (midtones).
- `luminance` (string): Which tonal band to select by brightness.
- `mode` (string, required): all: select the whole canvas. none: deselect. inverse: invert the current selection. rectangle: left/top/right/bottom (+optional feather_px). ellipse: left/top/right/bottom bounding box (+anti_alias,…
- `placement` (object): Grounded coordinates (rectangle/ellipse/magic_wand): NAME anchors + a relation instead of guessing pixels. rectangle/ellipse ← a REGION relation (inside/gap) → the selection bounding box; magic_wand…
- `points` (array): Polygon vertices in ABSOLUTE document pixels: [{x, y}, ...], minimum 3. (0,0) is top-left. The ring auto-closes (last vertex connects back to the first). You must know the pixel coordinates to aim th…
- `red` (integer): Target red (0-255).
- `right` (number): Right edge in pixels
- `sample_all_layers` (boolean): If true, samples color across all visible layers. If false (default), samples the active layer only.
- `selection_type` (string): How this selection combines with any existing one. 'replace' (default) overwrites; 'add' unions with the existing selection; 'subtract' removes this from the existing; 'intersect' keeps only the over…
- `soft_mask` (boolean): False (default) yields a hard-edged selection — every pixel fully in or fully out, which is what you want before ps_modify_selection feathering. True lets Photoshop feather the focus falloff itself,…
- `tolerance` (integer): Color similarity tolerance (0-255). Default 32.
- `top` (number): Top edge in pixels
- `upper_limit` (integer): shadows/midtones: upper brightness bound (0-255). Default 65 (shadows) / 150 (midtones).
- `use_faces` (boolean): skin_tones only: refine the skin-tone selection using face detection. Default false (pure Lab skin-tone colour preset, no AI dependency).
- `x` (integer): Click X in document pixel coords.
- `y` (integer): Click Y in document pixel coords.

Output parameters:

- `active_layer_temporarily_changed` (boolean): mode=focus_area: true if the active layer was not an ordinary pixel layer and detection was temporarily retargeted to the bottom layer. Restored before return.
- `anti_alias` (boolean)
- `contiguous` (boolean)
- `deselected` (boolean)
- `feather_px` (number)
- `fuzziness` (number)
- `in_focus_radius` (number): mode=focus_area: radius used.
- `inverted` (boolean)
- `lower_limit` (number)
- `luminance` (string)
- `method` (string)
- `placement` (object)
- `point_count` (number)
- `preset` (string)
- `requested_bounds` (array)
- `sample_all_layers` (boolean)
- `sample_point` (object)
- `selected` (boolean)
- `selection` (string)
- `selection_info` (object): Rich post-op stats. Use these to verify the selection actually grabbed what was intended before committing it to a mask. `has_selection:false` short-circuits the rest of the fields (they will be abse…
- `selection_type` (string)
- `soft_mask` (boolean): mode=focus_area: soft_mask used.
- `strategy_used` (string): mode=focus_area: "executeAction:focusMask".
- `target_color` (object)
- `tolerance` (number)
- `upper_limit` (number)
- `warning` (string|null): mode=focus_area: set when whole_canvas_selected is true.
- `whole_canvas_selected` (boolean): mode=focus_area: true when the RAW detection (before any selection_type combine) covered essentially the entire canvas — usually a non-result. selection_info reports the FINAL, post-combine selection…

### `ps_modify_selection` (~847 tokens)

Modify the CURRENT selection — choose with `op`. (To create a NEW selection instead, use ps_select.) `feather` softens by radius_px (use when a selection was made hard, e.g. after select all/inverse, before applying an adjustment). `refine_edge` runs Select-and-Mask's global sliders headlessly (smooth, feather, contrast, shift_edge, edge-detection radius, decontaminate) to clean halos and soft/fuzzy edges (hair) after a rough color-range / magic-wand / subject selection. `expand` / `contract` grow / shrink the selection by `amount` px. `border` replaces the selection with an `amount`-px band around its edge. `smooth` rounds the corners with an `amount`-px radius. `grow` / `similar` expand the selection to similar-colour pixels by `tolerance` (+anti_alias) — `grow` to adjacent pixels only, `similar` document-wide. `transform` relatively scales (scale_x_percent / scale_y_percent), rotates (rotate_degrees) and/or translates (offset_x / offset_y) the marching ants — pixels are untouched. All require an active selection and return selection_info.

Input parameters:

- `amount` (number): Pixel amount: expand/contract distance, smooth radius, or border width. Required for expand/contract/border/smooth.
- `anti_alias` (boolean): Soften the selection edge. Default true.
- `at_canvas_bounds` (boolean): expand/contract/smooth: if true, the effect still applies where the selection meets the canvas edge. Default false.
- `contrast` (number): Edge contrast percent (0-100) — re-sharpens an over-soft edge.
- `decontaminate` (boolean): Decontaminate edge colors (removes color fringing).
- `feather` (number): Feather radius in pixels (0-1000) — softens the edge.
- `offset_x` (number): Translate the selection horizontally, pixels (relative). Default 0.
- `offset_y` (number): Translate the selection vertically, pixels (relative). Default 0.
- `op` (string, required): feather: soften the selection edge by radius_px. refine_edge: Select-and-Mask global sliders (smooth, feather, contrast, shift_edge, radius edge-detection, decontaminate) to clean halos / soft hair e…
- `radius` (integer): Edge-detection radius in pixels (0-250) — helps capture soft/fuzzy edges (hair).
- `radius_px` (number): Feather radius in pixels (must be > 0).
- `rotate_degrees` (number): Rotate the selection clockwise, degrees. Default 0.
- `scale_x_percent` (number): Horizontal scale of the selection, percent. Default 100 (no change).
- `scale_y_percent` (number): Vertical scale of the selection, percent. Default 100 (no change).
- `shift_edge` (number): Shift the edge inward (negative) or outward (positive), percent (-100 to 100).
- `smooth` (integer): Smooth the selection edge (0-100).
- `tolerance` (integer): Color similarity tolerance (0-255) for which neighbouring pixels are added. Default 32.

Output parameters:

- `amount_px` (number)
- `anti_alias` (boolean): op=grow/similar: anti_alias used.
- `contrast` (number)
- `decontaminate` (boolean)
- `feather` (number)
- `feathered` (boolean)
- `method` (string): op=grow/similar: "grow" or "similar".
- `mode` (string)
- `modified` (boolean)
- `offset_x` (number)
- `offset_y` (number)
- `output` (string)
- `radius` (number)
- `radius_px` (number)
- `refined` (boolean)
- `rotate_degrees` (number)
- `scale_x_percent` (number)
- `scale_y_percent` (number)
- `selected` (boolean): op=grow/similar: true on success.
- `selection_info` (object): Rich post-op stats. Use these to verify the selection actually grabbed what was intended before committing it to a mask. `has_selection:false` short-circuits the rest of the fields (they will be abse…
- `shift_edge` (number)
- `smooth` (number)
- `tolerance` (number): op=grow/similar: tolerance used.
- `transformed` (boolean)

### `ps_get_selection_preview` (~234 tokens)

Render an inline JPEG so the agent can visually verify what is currently selected: by default a red-wash OVERLAY (50% red over the selected area, Quick Mask-style — most intuitive); pass `image:'mask'` for a B/W MASK (black = selected, white = not) instead, or `image:'both'` for both. selection_info is always returned regardless of `image`. Heavier than the selection_info bundle alone (~2-4s) — call this when the stats look off or before committing a mask. Does NOT modify the source document.

Input parameters:

- `image` (string): Which rendered image(s) to return inline. 'overlay' (default): a 50% red wash over the selected area (Quick Mask-style — most intuitive). 'mask': a B/W mask (black=selected, white=not) instead. 'both…
- `max_dimension` (integer): Long-edge pixel cap for the returned images. Default 800.

Output parameters:

- `mask_bytes` (number)
- `max_dimension` (number)
- `overlay_bytes` (number)
- `rendered` (boolean)
- `selection_info` (object): Rich post-op stats. Use these to verify the selection actually grabbed what was intended before committing it to a mask. `has_selection:false` short-circuits the rest of the fields (they will be abse…

### `ps_layer_mask` (~493 tokens)

Manage the active layer's mask — choose with `op`. `create`: add a layer mask; if a selection is active it reveals the selection and hides the rest (the one-call "mask the placed image to the frame opening" — make the selection first, then create); with no selection, a reveal-all mask; adjustment layers load the current selection into their built-in mask. `delete`: remove the mask (layer pixels preserved). `apply`: DESTRUCTIVE — permanently bake the mask into the pixels (outside-mask pixels lost). `gradient`: draw a linear fade into the mask (fade_to names the side that ends hidden; start/end place the fade; auto-creates the mask; replaces existing mask content and clears any active selection first) — the standard fade for reflections, sky blends, and soft edge falloff. Verify with ps_get_preview. Prefer keeping masks non-destructive unless flattening for export. **Don't write `Mk Chnl At=Msk` or `Grdn` AM scripts in execute_script — this tool already does both.**

Input parameters:

- `end` (number): op=gradient: 0-1 fraction where the fade completes — fully hidden from here on. Must be greater than start.
- `extent` (string): op=gradient: measure start/end over the active layer's pixel bounds (default) or the whole canvas. A layer with no pixel bounds falls back to canvas.
- `fade_to` (string): op=gradient: the side that ends fully HIDDEN (mask black). The opposite side stays fully visible. E.g. a water reflection fades with fade_to=bottom.
- `op` (string, required): create: add a layer mask on the active layer (if a selection is active it reveals the selection — the "mask to the frame opening" answer; adjustment layers load the selection into their built-in mask…
- `start` (number): op=gradient: 0-1 fraction along the fade direction where the fade begins — the layer stays fully visible up to here.

Output parameters:

- `activeLayerKind` (string)
- `bounds_used` (object)
- `context` (object)
- `created_mask` (boolean): op=gradient: true when the reveal-all mask had to be created first.
- `extent` (string): op=gradient: 'layer' or 'canvas' — reports the extent actually used.
- `fade_to` (string)
- `from` (object): op=gradient: fully-visible end of the drawn fade, doc pixels.
- `hadSelection` (boolean)
- `layer_name` (string)
- `maskApplied` (boolean)
- `maskCreated` (boolean)
- `maskDeleted` (boolean)
- `mask_gradient` (boolean)
- `modifiedExistingMask` (boolean)
- `to` (object): op=gradient: fully-hidden end of the drawn fade, doc pixels.

### `ps_selection_channel` (~360 tokens)

Persist, restore, or manage a named Alpha channel — choose with `op`. `save`: store the current selection to channel_name (overwrites if it exists) so a complex AI/multi-step/feathered selection can be reloaded without rebuilding (throws if no active selection). `load`: restore a saved channel as the selection, with `operation` (replace|add|subtract|intersect) to combine — reapply one selection across layers. `duplicate`: copy an existing alpha/spot channel to a new one (optional new_channel_name). `delete`: remove an alpha/spot channel (won't touch the RGB/CMYK/Lab component channels).

Input parameters:

- `channel_name` (string, required): Name of the Alpha channel to restore. Must have been previously saved with ps_selection_channel (op=save).
- `new_channel_name` (string): duplicate only: name for the new channel. Optional — Photoshop auto-names it "<source> copy" when omitted.
- `op` (string, required): save: store the current selection to a named Alpha channel (channel_name; overwrites if it exists). load: restore a saved Alpha channel as the selection (channel_name + operation to combine). duplica…
- `operation` (string): How this selection combines with any existing one. 'replace' (default) overwrites; 'add' unions with the existing selection; 'subtract' removes this from the existing; 'intersect' keeps only the over…

Output parameters:

- `channel_count` (number): Total channels in the document after the op.
- `channel_name` (string)
- `deleted` (boolean)
- `duplicated` (boolean)
- `loaded` (boolean)
- `new_channel_name` (string)
- `operation` (string)
- `overwritten` (boolean): True if an existing channel with the same name was replaced.
- `saved` (boolean)
- `selection_info` (object): Rich post-op stats. Use these to verify the selection actually grabbed what was intended before committing it to a mask. `has_selection:false` short-circuits the rest of the fields (they will be abse…

### `ps_select_subject` (~296 tokens)

Run Photoshop's "Select Subject" (Adobe Sensei). One-call selection of the main subject — person, animal, product, etc. ~2-5s on typical images. Default sample_all_layers=true analyzes the full visible composite, which matches PS 2025 behavior and works around the PS 2026 "active layer only" default that fails opaquely when the active layer is a blurred / adjusted copy. Combines with existing selection via selection_type. Returns selection_info so the agent can verify area / edge complexity; if results look off, call ps_get_selection_preview for a visual. On failure, the error message lists fallbacks (Cloud processing in PS Preferences, manual UI selection).

Input parameters:

- `sample_all_layers` (boolean): If true (default), the model considers all visible layers — matches PS 2025 behavior and the user mental model of "select the subject of this image." If false, considers only the active layer (PS 202…
- `selection_type` (string): How this selection combines with any existing one. 'replace' (default) overwrites; 'add' unions with the existing selection; 'subtract' removes this from the existing; 'intersect' keeps only the over…

Output parameters:

- `active_layer_temporarily_changed` (boolean): True if we temporarily switched the active layer to the bottom layer during detection (to work around PS 2026 "active layer only" behavior when sample_all_layers=true). Original active layer is resto…
- `method` (string)
- `sample_all_layers` (boolean)
- `selected` (boolean)
- `selection_info` (object): Rich post-op stats. Use these to verify the selection actually grabbed what was intended before committing it to a mask. `has_selection:false` short-circuits the rest of the fields (they will be abse…
- `selection_type` (string)
- `strategy_used` (string): "dom:selectSubject" (preferred — DOM method, PS handles descriptor internals) or "executeAction:autoCutout" (legacy AM fallback). Telemetry surface: lets us see in the field whether the DOM path need…

### `ps_select_sky` (~166 tokens)

Run Photoshop's "Select Sky" (Adobe Sensei, PS 2021+). One-call sky masking for landscape work. Default sample_all_layers=true analyzes the full visible composite. Returns selection_info — high edge_complexity on tricky horizons (foreground objects against sky) is the signal to verify with ps_get_selection_preview before committing.

Input parameters:

- `sample_all_layers` (boolean): If true (default), the sky model considers all visible layers — the correct setting for most workflows. If false, considers only the active layer.
- `selection_type` (string): How this selection combines with any existing one. 'replace' (default) overwrites; 'add' unions with the existing selection; 'subtract' removes this from the existing; 'intersect' keeps only the over…

Output parameters:

- `active_layer_temporarily_changed` (boolean): True if active layer was temporarily switched to the bottom layer during detection. Restored before return.
- `method` (string)
- `sample_all_layers` (boolean)
- `selected` (boolean)
- `selection_info` (object): Rich post-op stats. Use these to verify the selection actually grabbed what was intended before committing it to a mask. `has_selection:false` short-circuits the rest of the fields (they will be abse…
- `selection_type` (string)
- `strategy_used` (string): "dom:selectSky" (preferred DOM method when exposed) or "executeAction:selectSky" (AM fallback).

### `ps_undo` (~155 tokens)

Step backward in the document history (equivalent to Ctrl/Cmd+Z). WHEN TO REACH FOR THIS: after an experimental destructive bake (ps_merge mode=visible/flatten, ps_filter op=apply type=*_blur/sharpen/noise) produced a wrong result; after a play_action whose scope you mispredicted; or to revert an entire branch of exploration. Non-destructive workflows (adjustment layers + masks) rarely need this — just tweak/delete the offending layer instead. Reversible via ps_redo as long as no new edit has been made since. Returns current history state, remaining steps, and document context.

Input parameters:

- `steps` (integer): Number of steps to undo (default: 1)

Output parameters:

- `availableRedoSteps` (number)
- `context` (object)
- `currentHistoryState` (string)
- `redone` (boolean)
- `remainingStates` (number)
- `steps` (number)
- `undone` (boolean)

### `ps_redo` (~68 tokens)

Step forward in the document history (equivalent to Ctrl/Cmd+Shift+Z). Only works if ps_undo was the last operation; making a fresh edit destroys the redo stack. Returns updated context.

Input parameters:

- `steps` (integer): Number of steps to redo (default: 1)

Output parameters:

- `availableRedoSteps` (number)
- `context` (object)
- `currentHistoryState` (string)
- `redone` (boolean)
- `remainingStates` (number)
- `steps` (number)
- `undone` (boolean)

### `ps_move_layer_to_position` (~309 tokens)

Move a layer to a position in the stack — the single ordering primitive (the per-direction helpers `_to_top` / `_to_bottom` / `_up` / `_down` were removed 2026-05-31; this tool covers all four cases). Position keywords: ABOVE/BELOW (requires target_layer_name — places the moved layer immediately above/below the target), TOP/BOTTOM (absolute — target_layer_name not needed). By default the ACTIVE layer is moved; pass layer_to_move=<name> to move a specific layer by name (recurses into groups). COMMON CASES: an adjustment layer just created landed below another adjustment that masks its effect → move it to TOP; a vignette darkens the wrong layers → move ABOVE the layer it should affect; a sky-replacement composite is showing through the foreground → move the foreground to TOP. Idempotent for a given (layer_to_move, target, position).

Input parameters:

- `layer_to_move` (string): Optional: name of the layer being moved. If omitted, the active layer is moved (legacy behaviour).
- `position` (string, required): Where to move the layer. ABOVE/BELOW = relative to target_layer_name (which is then REQUIRED); TOP/BOTTOM = absolute top/bottom of the layer stack (target_layer_name not needed). Uppercase required.
- `target_layer_name` (string): Required for ABOVE/BELOW: the layer to move relative to. Ignored for TOP/BOTTOM.

Output parameters:

- `context` (object)
- `direction` (string)
- `layerName` (string)
- `message` (string)
- `moved` (boolean)
- `position` (string)
- `relativeTo` (string)

### `ps_get_preview` (~575 tokens)

Render the active Photoshop document as a flattened, downscaled image and return it inline so the calling AI can see the current visual state. Use this to verify edits visually, judge whether adjustments went too far or not far enough, and decide what to do next. Read-only with respect to the working document (renders a duplicate that is closed immediately). The optional `annotations` array draws overlays in document-space coordinates: `rectangle` / `guide` / `point` / `selection` for spatial verification, and `grid` / `composition` for coordinate readout and compositional evaluation (added 2026-06-09 — grid styles `every` / `thirds` / `quarters` / `phi`, composition styles `diagonals` / `triangles` / `fibonacci_grid` / `golden_spiral`). Use spatial annotations to verify ("did the placed image land inside the frame interior?") — pass both target and actual bounds in different colors. Use grid / composition annotations to EVALUATE composition (balance, thirds, leading lines, focal-point placement) — not to read a coordinate for a tool call. To place or select precisely, do NOT read a pixel off a grid (unreliable) — NAME the intent to the on-device perception tools instead: `ps_detect` (COCO objects → real document-pixel boxes), `ps_select_by_reference` (a named target → a real selection, not a guessed rectangle), plus any spatial-grounding locator / selection tools present in `tools/list`. Without annotations, behaves identically to a plain preview.

Input parameters:

- `annotations` (array): Optional list of visual annotations to draw onto the preview before rendering — rectangles (by explicit bounds OR by layer name), guides (horizontal / vertical reference lines), point markers, and th…
- `max_dimension` (integer): Cap on the long edge in pixels. Defaults to 1024, which is plenty for tone/color/composition judgment and roughly halves the base64 payload vs the older 1500 default. Bump higher only when reading fi…
- `quality` (integer): JPEG quality 1-12. Default: 6 (visibly clean for verification at the default 1024px max-dim; halves payload vs the older quality=8 default). Bump to 8-10 only when the preview is the deliverable, not…

Output parameters:

- `annotation_count` (number)
- `bytes` (number)
- `context` (object)
- `dimensions` (string)
- `format` (string)
- `mime_type` (string)

### `ps_get_layer_bounds_diff` (~253 tokens)

Numeric verification: compute the per-edge pixel deltas between a layer's actual bounds and a target rectangle. Returns left/top/right/bottom deltas (actual − target), scale ratio (actual_size / target_size), centroid offset, and a one-word verdict ("aligned", "shifted right", "layer too small", etc.). Use this AFTER place_image / scale_layer / move_layer to confirm the operation produced the intended result — far more reliable than eyeballing a preview for fine alignment. Read-only. Layers nested in groups are found by name recursively.

Input parameters:

- `layer` (string, required): Name of the layer to measure. Reads boundsNoEffects (raw pixel bounds without layer-style expansion). The active doc's layer tree is searched recursively (so layers nested in groups are findable by n…
- `target_bottom` (number, required): Target rectangle bottom edge.
- `target_left` (number, required): Target rectangle left edge in document pixels.
- `target_right` (number, required): Target rectangle right edge.
- `target_top` (number, required): Target rectangle top edge.
- `tolerance_px` (number): Tolerance in pixels for the verdict — within this delta on every edge, the verdict is "aligned". Default 10.

Output parameters:

- `actual_bounds` (object)
- `centroid_offset_x` (number)
- `centroid_offset_y` (number)
- `context` (object)
- `deltas` (object)
- `scale_ratio_x` (number)
- `scale_ratio_y` (number)
- `target_bounds` (object)
- `verdict` (string)
- `within_tolerance` (boolean)

### `ps_get_histogram` (~410 tokens)

Whole-image (or per-channel) histogram — the quantitative answer to questions get_preview can't reliably answer by eye. Returns 256 bin counts plus mean / stdev / median. Cheap (~50ms), read-only. **Reach for this when**: (a) clipping detection — bins 0 and 255 carry the count of crushed shadows / blown highlights; you can't see clipping reliably in a downsampled JPEG preview; (b) exposure verification after a levels/curves/exposure adjustment — confirm the histogram actually shifted; (c) "is this image neutral-gray?" — compare R / G / B channel means; (d) confirming a destructive op did anything (two identical histograms = no-op regardless of the tool's success message). Composite reads the visible flattened image (any color mode). Per-channel reads require the document have that channel.

Input parameters:

- `channel` (string): Which channel to read. "composite" (default) is the visible flattened image; if the active layer is an adjustment/fill/shape layer the tool transparently switches to a pixel layer to read it. "red"/"…

Output parameters:

- `bin_count` (number)
- `bins` (array)
- `channel` (string)
- `context` (object)
- `mean` (number)
- `median` (number)
- `stdev` (number)
- `total_pixels` (number)

### `ps_compare_regions` (~300 tokens)

Quantitative region comparison — the NUMERIC verification answer when "does it look right?" via get_preview is too subjective. Captures the histogram of two rectangular regions on the same document and reports per-channel mean / stdev / median for each region plus the deltas. **Reach for this when**: (a) "did the placed image match the room's lighting?" — sample a region of the placed image vs a region of the surrounding wall; (b) "did this adjustment do anything visible in the shadows?" — sample the same dark region before and after; (c) "is region A noticeably warmer/cooler than region B?" — read the channel means directly. Single-pixel sampling via a 1×1 rect is supported. Read-only.

Input parameters:

- `label_a` (string): Optional label for region A in the response.
- `label_b` (string): Optional label for region B in the response.
- `region_a_bottom` (number, required): Region A bottom edge.
- `region_a_left` (number, required): Region A left edge.
- `region_a_right` (number, required): Region A right edge.
- `region_a_top` (number, required): Region A top edge.
- `region_b_bottom` (number, required): Region B bottom edge.
- `region_b_left` (number, required): Region B left edge.
- `region_b_right` (number, required): Region B right edge.
- `region_b_top` (number, required): Region B top edge.

Output parameters:

- `context` (object)
- `differences` (object)
- `region_a` (object)
- `region_b` (object)

### `ps_inspect` (~336 tokens)

Read-only document inspection — choose with `what` (metadata / layer_tree / history / selection_info / smart_object). This is the assess/orientation surface: call it at the start of a workflow and whenever you need fresh state. For metadata, pass `sections` to subset (e.g. ["context"] for a cheap probe). For an IMAGE-based check use ps_get_preview; for NUMERIC verification use ps_get_histogram / ps_compare_regions / ps_get_layer_bounds_diff (these stay separate, named tools on purpose). Read-only and idempotent.

Input parameters:

- `sections` (array): Optional subset of sections to return. Omit for all sections. The context block (active doc + layer + selection state) is always returned regardless. Use ["context"] for a cheap orientation call that…
- `what` (string, required): Which read-only state to return. metadata: document/IPTC/camera-EXIF/GPS/ACR develop settings + active context (optionally subset with `sections`; sections=["context"] is the cheap orientation probe)…

Output parameters:

- `acr` (object)
- `activeLayer` (string)
- `bounds` (array)
- `camera` (object)
- `canRedo` (boolean)
- `canUndo` (boolean)
- `context` (object)
- `currentIndex` (number)
- `currentState` (string)
- `document` (object)
- `documentName` (string)
- `document_id` (string|null)
- `file_reference` (string|null)
- `gps` (object)
- `iptc` (object)
- `is_smart_object` (boolean)
- `layer_kind` (string)
- `layer_name` (string)
- `linked` (boolean)
- `placed` (string|null)
- `selection_info` (object)
- `smart_filter_count` (number)
- `source_metadata` (object)
- `states` (array)
- `topLevelCount` (number)
- `totalStates` (number)
- `tree` (array)

### `ps_overview` (~85 tokens)

Orientation brief for the entire MCP — workflow contract, capabilities map by category, verification primitives, escape-hatch policy, known gaps. READ THIS FIRST when the user gives you an open-ended editing task. Read-only, idempotent, no document required, no Photoshop call (returns a static markdown brief). Skip it for trivial single-tool requests where you already know which tool fits.

Output parameters:

- `bytes` (number)
- `sections` (array)

### `ps_report_problem` (~195 tokens)

Collect an ANONYMIZED diagnostic bundle and write it to the user's Downloads folder so they can attach it to a bug report — use when Editmamei misbehaves (won't connect, a tool keeps failing, unexpected results). The bundle holds recent server logs, system info (Editmamei/OS/Photoshop versions), and a content-free summary of recent tool calls (name, success, duration, error class). It contains NO image content, NO tool arguments, and file paths reduced to basenames. Does not touch Photoshop; writes one JSON file. After calling, tell the user the file path and that they can attach it to a new issue at https://github.com/editmamei/editmamei/issues.

Input parameters:

- `note` (string): Optional short description of the problem (what went wrong, what you were doing). Embedded verbatim after sanitization. No file contents or paths needed.

Output parameters:

- `bytes` (number)
- `desktop_log_included` (boolean)
- `issues_url` (string)
- `path` (string)
- `recent_session_count` (number)
- `server_log_lines` (number)

### `ps_retouch` (~895 tokens)

Selection-driven content-aware retouch — choose the technique with `method`. Requires an active selection (throws if none, so Content-Aware Fill never silently fills the whole layer). Auto-duplicates the active layer by default so the original is preserved (auto-duplicate-first); pass `apply_to_active_layer: true` to bake into the original. `content_aware_fill` synthesizes a fill from surroundings (remove wires/objects/blemishes); `patch` samples replacement pixels from a chosen offset — or NAME the source region with `source_placement` (grounded + gated); `content_aware_move` relocates the selection and fills the source — offset, or NAME where with `destination_placement`.

Input parameters:

- `apply_to_active_layer` (boolean): If false (default), the retouch op is applied to a duplicate of the active layer named "<OpName> (<Original Name>)" — the original is preserved and the LLM can undo simply by deleting the copy. If tr…
- `blend_mode` (string): Blend mode for the fill. Default `normal`. Use `multiply` or `darken` when filling around hair to keep darker edges; `lighten` for highlights.
- `color_adaptation` (boolean): When true (default), PS adjusts the synthesized fill to match the surrounding region's color. Turn off only when matching color would compromise structure.
- `destination_placement` (object): Grounded alternative to offset_x/offset_y: NAME where to move the selection (resolves to a POINT via the grounding resolver + objective gate — a grid intersection, an object centroid, an extremum). T…
- `heal_smooth_factor` (integer): Internal smoothing factor (0-10). Default 5.
- `method` (string, required): Retouch technique (all require an active selection). content_aware_fill: synthesize a fill from surrounding content (color_adaptation, opacity, blend_mode, rotate/scale/mirror). patch: sample replace…
- `mirror` (boolean): Allow PS to mirror sampled patches when synthesizing. Default false.
- `offset_x` (number): Horizontal pixel delta to move the selected content. Positive = right. Required unless destination_placement is given.
- `offset_y` (number): Vertical pixel delta to move the selected content. Positive = down. Required unless destination_placement is given.
- `opacity` (integer): Fill opacity 1-100%. Default 100.
- `patch_color` (integer): Options bar > Color slider (0-10). Default 5.
- `patch_structure` (integer): Options bar > Structure slider (1-7). Default 4 (CAM default).
- `reshuffle` (boolean): Allow PS to recompose the moved content from non-contiguous source pixels. Default true (Photoshop default for CAM).
- `rotate` (boolean): Allow PS to rotate sampled patches when synthesizing. Default false (Photoshop default).
- `sample_all_layers` (boolean): Sample from all visible layers. Default false.
- `scale` (boolean): Allow PS to rescale sampled patches when synthesizing. Default false.
- `source_placement` (object): Grounded alternative to offset_x/offset_y: NAME the patch SOURCE (resolves to a POINT via the grounding resolver + objective gate — e.g. an extremum for the cleanest nearby skin, a grid intersection)…
- `transparent` (boolean): Respect layer transparency. Default false.
- `use_source` (boolean): When true (default), the user-drawn selection is the patch source — the natural "patch this region" semantic. False inverts to destination-mode patching.

Output parameters:

- `context` (object)
- `original_layer_name` (string)
- `retouch` (string)
- `target_layer_name` (string)
- `target_was_copy` (boolean)

### `ps_transform_canvas` (~177 tokens)

Transform the whole document (canvas + all layers), not a single layer — choose with `op`. `rotate` spins the canvas by degrees (+cw; pass 90/180/-90 for quarter/half turns). `flip` mirrors the canvas horizontal|vertical. For rotating/flipping ONE layer use ps_transform_layer instead.

Input parameters:

- `degrees` (number): Rotation angle in degrees, positive = clockwise. Any value (incl. 90 / 180 / -90 for quarter/half turns).
- `op` (string, required): Which document-level transform to apply. rotate: spin the whole canvas by degrees (+cw; 90/180/-90 for quarter/half turns). flip: mirror the whole canvas horizontal|vertical.
- `orientation` (string): 'horizontal' mirrors the canvas left-right; 'vertical' mirrors top-bottom.

Output parameters:

- `axis` (string)
- `degrees` (number)
- `flipped_canvas` (boolean)
- `rotated_canvas` (boolean)

### `ps_guides` (~284 tokens)

Manage document guides — non-printing layout aids for a HUMAN working in Photoshop. Guides are editor-only chrome: they do NOT render into ps_get_preview (the exported/flattened image), so they are a user authoring aid, not a model-perception tool — place them when a person will open the PSD and wants alignment/composition marks. Choose with `op`. `add` places one guide (orientation horizontal|vertical) at a `position` in px. `layout` creates an evenly-spaced grid (columns and/or rows — great for rule-of-thirds at 3×3). `clear` removes all guides.

Input parameters:

- `columns` (integer): Number of evenly-spaced columns (vertical guides). 0 = none.
- `op` (string, required): Guide operation. add: one guide at position (orientation + position px). layout: an evenly-spaced grid (columns and/or rows). clear: remove ALL guides from the document.
- `orientation` (string): 'vertical' adds a top-to-bottom guide positioned by its x coordinate; 'horizontal' adds a left-to-right guide positioned by its y coordinate.
- `position` (number): Guide position in document pixels (the x for a vertical guide, the y for a horizontal guide).
- `rows` (integer): Number of evenly-spaced rows (horizontal guides). 0 = none.

Output parameters:

- `columns` (number)
- `guide_added` (boolean)
- `guide_layout_created` (boolean)
- `guides_cleared` (boolean)
- `orientation` (string)
- `position` (number)
- `rows` (number)

### `ps_detect` (~375 tokens)

The cheap, narrow read: labeled bounding boxes only — faces and/or COCO-80 objects (person, dog, car, chair, sofa, …) in DOCUMENT-pixel space. LOCAL on-device computer vision; the image is never sent anywhere. Use this for real coordinates before a spatially-targeted edit when boxes are all you need — far more reliable than estimating positions from a preview. For the full scene model (regions, horizon, tonal zones, composition, and a menu of selectable named regions), use ps_read_scene instead. `target` selects faces / objects / both. Read-only: renders a throwaway duplicate, never modifies the working document. Boxes are [x1, y1, x2, y2]. Pass `annotate:true` for an annotated preview JPEG (faces cyan, objects magenta) when you need to visually confirm a surprising result.

Input parameters:

- `annotate` (boolean): Also return an annotated preview JPEG with the detected boxes drawn (faces cyan, objects magenta). Default false: the labeled boxes returned by this call are already complete on their own — ask for t…
- `face_threshold` (number): Minimum face confidence (0–1).
- `max_dimension` (number): Long-edge pixels of the JPEG the detectors run on. Smaller is faster; the models downscale internally so 1024 is plenty. Returned coordinates are always in full document pixels regardless.
- `max_objects` (number): Cap on returned objects, highest-confidence first.
- `object_threshold` (number): Minimum object confidence (0–1).
- `target` (string): What to detect: 'faces' (forward-facing faces), 'objects' (COCO-80 classes: person, dog, car, chair, …), or 'both'.

Output parameters:

- `backends` (object)
- `context` (object)
- `faces` (array)
- `image` (object)
- `objects` (array)

### `ps_path` (~1017 tokens)

Work with editable vector PATHS — the connective tissue between selections, brush strokes, and clipping. One op-discriminated tool: `create_from_selection` (selection → work path), `create_from_placement` (NAME a curve → editable saved path, the grounded pen), `save` (name the work path), `list`, `delete`, `load_as_selection` (path → selection), `stroke` (paint a brush-family tool along a path), `fill` (fill a path region), `set_clipping` (mark a saved path as the clipping path). **Reach for this when**: tracing a named curve (an edge, a landmark contour) into an editable path, turning a precise selection into a reusable/strokeable outline, converting a saved path back to a selection, or outlining/filling a shape exactly. create_from_selection and load_as_selection are an exact round-trip. stroke/fill bake pixels and auto-duplicate the target layer. Every op returns path_info (counts + per-path subpath/anchor totals) so you can verify the path landed; load_as_selection also returns selection_info.

Input parameters:

- `anti_alias` (boolean): load_as_selection / fill: anti-alias the edge. Default true.
- `apply_to_active_layer` (boolean): If false (default), the stroke / fill op is applied to a duplicate of the active layer named "<OpName> (<Original Name>)" — the original is preserved and the LLM can undo simply by deleting the copy.…
- `closed` (boolean): create_from_placement only: close the path into a loop (connect the last anchor back to the first). Default false (an open path).
- `color` (object): fill only: RGB fill color (each 0-255). Default black.
- `feather` (number): load_as_selection / fill: soften the result edge by this many pixels. Default 0.
- `flatness` (number): set_clipping only: device-pixel flatness for the clipping path (0.2-100; higher = coarser curve approximation). Omit for the PS default.
- `mode` (string): fill only: blend mode for the fill. Default 'normal'.
- `name` (string): Path name. REQUIRED for save, set_clipping, and create_from_placement (the new saved path is named). Optional for delete / load_as_selection / stroke / fill — when omitted those target the current wo…
- `op` (string, required): create_from_selection: convert the active selection into a work path (tolerance = crude↔detailed dial; CLEARS the selection). create_from_placement: NAME a curve (placement → a path relation: `along`…
- `opacity` (number): fill only: fill opacity percent (0-100). Default 100.
- `operation` (string): load_as_selection only: how the loaded selection combines with any existing one. Default 'replace'.
- `placement` (object): create_from_placement only: NAME the curve the path follows, as an anchor-relational placement that resolves to a PATH (relation `along` a traced edge / a Pro landmark curve, or a `segment` between t…
- `tolerance` (number): create_from_selection only: makeWorkPath tolerance in pixels (0.5 = hug every detail → 10 = crude). Default 2.
- `tool` (string): stroke only: which brush-family tool paints the path (see this field's own enum for the full supported set). Default 'brush'.

Output parameters:

- `anchors` (number)
- `clipping_path_set` (boolean)
- `closed` (boolean)
- `context` (object)
- `count` (number)
- `created` (boolean)
- `deleted` (boolean)
- `filled` (boolean)
- `loaded` (boolean)
- `mode` (string)
- `name` (string)
- `operation` (string)
- `original_layer_name` (string)
- `path_info` (object)
- `path_name` (string)
- `paths` (array)
- `placement` (object)
- `saved` (boolean)
- `selection_consumed` (boolean)
- `selection_info` (object)
- `stroked` (boolean)
- `target_layer_name` (string)
- `target_was_copy` (boolean)
- `tolerance` (number)
- `tool` (string)
- `tool_type` (string)

### `ps_vector_mask` (~376 tokens)

Attach, remove, (un)link, or (dis/en)able a layer VECTOR MASK — the path-driven, resolution-independent companion to a pixel layer mask. Ops: `add` (from the active path via source=from_current_path — the typical flow after ps_path op=create_from_selection / save — or an empty source=reveal_all/hide_all mask), `delete`, `link`, `unlink`, `disable` (turn the mask off without deleting it), `enable` (turn it back on). **Reach for this when** you want a crisp vector-edged mask rather than a painted pixel mask. `add` needs a non-background layer (and a path for from_current_path); the other ops need a layer that already has a vector mask. (Vector masks are AM-driven; verified live on PS 27.2.0.)

Input parameters:

- `op` (string, required): add: create a vector mask on the active layer — seeded from the active path (source=from_current_path, needs a path from ps_path) or as an empty reveal_all/hide_all mask (no path needed). delete: rem…
- `source` (string): add only: what the vector mask is seeded from. 'from_current_path' = the active work/saved path (needs a path; the main consumer of ps_path). 'reveal_all' = an empty mask that reveals the whole layer…

Output parameters:

- `context` (object)
- `layer_name` (string)
- `source` (string)
- `vector_mask_added` (boolean)
- `vector_mask_deleted` (boolean)
- `vector_mask_enabled` (boolean)
- `vector_mask_linked` (boolean)

### `ps_apply_image` (~376 tokens)

Composite a source layer + channel onto the ACTIVE layer using a calculation blend mode (Image ▸ Apply Image). **Reach for this** for luminosity blends, frequency-separation re-blends, texture overlays, or pulling one channel into another. Source = a layer (merged or named) and a channel (rgb/red/green/blue/alpha). Bakes into pixels, so by default it runs on a DUPLICATE of the active layer (set apply_to_active_layer=true to bake in place). The active layer must be a normal pixel layer. (AM-only; verified live on PS 27.2.0.)

Input parameters:

- `apply_to_active_layer` (boolean): If false (default), the composite is applied to a duplicate of the active layer named "<OpName> (<Original Name>)" — the original is preserved and the LLM can undo simply by deleting the copy. If tru…
- `blend` (string, required): Calculation blend mode: how the source combines with the target. multiply (darken/texture), screen (lighten), overlay/soft_light/hard_light (contrast), difference/exclusion/subtract/add (channel math…
- `opacity` (integer): Blend opacity 0-100. Default 100 (full strength).
- `source_alpha_name` (string): Required when source_channel='alpha': the name of the alpha channel to read.
- `source_channel` (string): Source channel: 'rgb' (the composite, default), a single 'red'/'green'/'blue' channel, or 'alpha' (then set source_alpha_name).
- `source_layer` (string): Which layer to pull the source from: 'merged' (the flattened composite, default) or an exact layer name.

Output parameters:

- `applied` (boolean)
- `blend` (string)
- `context` (object)
- `opacity` (number)
- `source_channel` (string)
- `source_layer` (string)
- `target_layer_name` (string)
- `target_was_copy` (boolean)

### `ps_calculations` (~338 tokens)

Blend TWO sources (each a layer + single channel) into a NEW alpha channel via a calculation blend mode (Image ▸ Calculations). **Reach for this** to build advanced selections/masks from channel math — e.g. difference of two channels to isolate edges, or multiply two channels for a luminosity mask. Non-destructive: adds a new channel (delete it to revert); the result is loadable as a selection via ps_selection_channel op=load. (AM-only; verified live on PS 27.2.0.)

Input parameters:

- `blend` (string, required): Calculation blend mode: how the source combines with the target. multiply (darken/texture), screen (lighten), overlay/soft_light/hard_light (contrast), difference/exclusion/subtract/add (channel math…
- `opacity` (integer): Blend opacity 0-100. Default 100.
- `source1_alpha_name` (string): Required when source1_channel='alpha'.
- `source1_channel` (string): Source 1 channel: a single 'red'/'green'/'blue' channel, or 'alpha' (+ name).
- `source1_layer` (string): Source 1 layer: 'merged' (default) or an exact layer name.
- `source2_alpha_name` (string): Required when source2_channel='alpha'.
- `source2_channel` (string): Source 2 channel: a single 'red'/'green'/'blue' channel, or 'alpha' (+ name).
- `source2_layer` (string): Source 2 layer: 'merged' (default) or an exact layer name.

Output parameters:

- `blend` (string)
- `calculated` (boolean)
- `channel_count` (number)
- `context` (object)
- `new_channel_name` (string)
- `opacity` (number)

### `ps_shape` (~787 tokens)

Draw a vector SHAPE layer — `rectangle` (optionally rounded via corner_radius), `ellipse`, or `line` — filled with a solid color, optionally stroked. Hoisted out of the active layer's group by default even though the underlying Mk-contentLayer descriptor carries no placement target and would otherwise nest the new layer INSIDE that group (pass into_active_group:true to keep that native nesting). Aim it EITHER by anchor-relational `placement` (preferred: name anchors + a relation and the resolver computes the geometry, verified by an objective gate — no pixel-guessing; rectangle/ellipse ← a region relation, line ← a path relation) OR by ABSOLUTE document pixels (top-left origin: rectangle/ellipse take left/top/right/bottom; line takes start_x/start_y → end_x/end_y plus weight — you must know the pixel positions, so prefer the anchor-relational `placement` path above and verify the result with a preview). Creates a new vector layer (non-destructive — delete it to remove). (AM-only; verified live on PS 27.2.0.)

Input parameters:

- `bottom` (number): rectangle/ellipse: bounding-box bottom edge, document px.
- `corner_radius` (number): rectangle only: corner radius in px. 0 (default) = sharp corners; >0 = rounded.
- `end_x` (number): line: end point X, document px.
- `end_y` (number): line: end point Y, document px.
- `fill_color` (object): Fill color (the line color for type=line). RGB 0-255. Default black.
- `into_active_group` (boolean): Photoshop's Mk-contentLayer descriptor carries no placement target, so with a GROUP active it would natively nest the new shape layer INSIDE that group. Default false hoists the new layer back out so…
- `left` (number): rectangle/ellipse: bounding-box left edge, document px.
- `placement` (object): ANCHOR-RELATIONAL placement (preferred over guessing pixels): rectangle/ellipse ← a region relation (inside/gap) → the resolved region bounding box; line ← a path relation (along/offset-curve over a…
- `right` (number): rectangle/ellipse: bounding-box right edge, document px.
- `start_x` (number): line: start point X, document px.
- `start_y` (number): line: start point Y, document px.
- `stroke_color` (object): rectangle/ellipse stroke color when stroke_width>0. RGB 0-255. Default black.
- `stroke_width` (number): rectangle/ellipse: outline width in px. 0 (default) = no stroke (fill only). Ignored for line (use weight).
- `top` (number): rectangle/ellipse: bounding-box top edge, document px.
- `type` (string, required): rectangle: a box (left/top/right/bottom; corner_radius>0 rounds the corners). ellipse: an oval in the left/top/right/bottom bounding box. line: a straight line from (start_x,start_y) to (end_x,end_y)…
- `weight` (number): line only: line thickness in px. Default 4.

Output parameters:

- `context` (object)
- `hoisted` (boolean): True when the new layer had to be moved back out of the previously-active group to honor into_active_group:false (the default). False when it landed correctly on its own, or when the move-back itself…
- `layer_name` (string)
- `parent_path` (array|null): The containing-group name chain (outermost first), empty array at the document root.
- `placement` (object): Present when anchor-relational placement was used: the resolved geometry + gate verdict.
- `shape_created` (boolean)
- `shape_type` (string)
- `stroked` (boolean)

### `ps_replace_sky` (~427 tokens)

Run Photoshop's Sky Replacement (Adobe Sensei): detect the sky, composite a replacement, and relight/colour-grade the foreground to match. Non-destructive — everything lands in a "Sky Replacement Group" of editable layers above the original, so the result can be tuned or deleted afterwards. sky_file takes an ABSOLUTE path to ANY image on disk, not only Photoshop's built-in presets. Reach for harmonization_opacity and foreground_lighting_opacity when the composite reads as pasted-on; those two carry most of the believability. Fails cleanly when the image has no detectable sky (indoor or closed compositions).

Input parameters:

- `border_smoothness` (number): Softens the boundary between sky and foreground. 0 is a hard cut.
- `brightness` (number): Brightness of the replaced sky itself.
- `edge_lighting_opacity` (number): Strength of the light wrap along the foreground edge where it meets the sky.
- `foreground_lighting_opacity` (number): Strength of the relighting applied to the foreground so it appears lit by the new sky.
- `harmonization_opacity` (number): How strongly the foreground is colour-graded to match the new sky. This is what sells the composite — 0 leaves the foreground untouched and usually reads as pasted-on.
- `shift_edge` (number): Moves the sky/foreground boundary inward (negative) or outward (positive). Use it when the horizon leaves a halo or eats into the foreground.
- `sky_file` (string, required): ABSOLUTE path to the image to use as the sky. Any image Photoshop can open works — it does not need to be a registered Photoshop sky preset. The built-in skies live as .jpg files under the Sky_Preset…
- `sky_name` (string): Label recorded on the operation. Cosmetic — it does not select the sky, sky_file does.
- `temperature` (number): Warms (positive) or cools (negative) the replaced sky.

Output parameters:

- `context` (object)
- `group_layers` (array): Layers inside the group, top to bottom — typically the sky layer, an edge-lighting group, a foreground-lighting layer and a foreground-colour curves layer.
- `group_name` (string): Name of the layer group Photoshop created.
- `replaced` (boolean)
- `sky_file` (string)
- `sky_name` (string)
- `strategy_used` (string)

### `ps_read_scene` (~561 tokens)

The full scene model — run this before a spatially-targeted edit, not the cheaper ps_detect: detected subjects (with the main one flagged) and faces in document pixels, a coarse sky/ground region map, the horizon line (y + placement + confidence), tonal zones (shadow/midtone/highlight bands + coverage), composition geometry (which thirds cell the subject sits in, balance, headroom), and the menu of selectable named regions. The structured model is complete on its own — pass `annotate:true` for an annotated preview JPEG when you actually need to see it drawn. Built using LOCAL on-device vision + classical CV; the image never leaves the machine. Select regions by name with ps_select_by_reference instead of guessing a rectangle. Read-only: renders a throwaway duplicate. Perception is cached per document state, so repeated reads are cheap.

Input parameters:

- `annotate` (boolean): Also return an annotated preview JPEG with subject boxes (magenta), faces (cyan), and the horizon line (yellow) drawn. Default false: the structured scene model returned by this call is already compl…
- `composition_context` (object): Optional: tune the confidence gate for an artistic/non-standard composition (e.g. profile:big_sky) so a legitimately large region is not rejected. Same shape as ps_select_by_reference.
- `max_dimension` (number): Long-edge px of the perception export. Returned coordinates are always in full document pixels.
- `refresh` (boolean): Force a fresh perception pass even if a cached model for the current document state exists. Perception is normally cached per (document, history-state) so it runs once per state.
- `save_regions` (boolean): EAGERLY derive every region (sky/ground/shadows/highlights/skin/subject/face) up front and SAVE each confident one as a managed `scene:*` alpha channel, so the returned menu carries a verified method…

Output parameters:

- `composition` (object)
- `doc` (object)
- `faces` (array)
- `horizon` (object)
- `provenance` (object)
- `region_menu` (array)
- `regions` (array)
- `subjects` (array)
- `tonal_zones` (object)

### `ps_select_by_reference` (~784 tokens)

Select a region by NAME instead of coordinates — the natural-mask alternative to a rectangle — with a CONFIDENCE GATE. target=sky/ground/foliage/subject/face/shadows/highlights/skin/above_horizon resolves through the right Photoshop-native method (threshold for sky, invert-sky−subjects for ground, luminance for shadows/highlights, skin-tone colour ∩ the subject box, the detected face/subject box) and is SCORED before it is offered: a clean region is left selected; an unconfident one is NOT selected and reported as honest absence (the city with no real sky gets no sky). Pro adds precise FACE-FEATURE targets backed by the face mesh — face_skin (the retouch mask: face minus eyes/brows/lips), face_eyes, face_brows, face_lips, face_teeth (mouth opening), face_nose, face_under_eye, face_cheeks — each a real geometry-following selection, derived on first request and then saved as a scene:face_* channel so repeats load instantly. `passed`/`confidence` are returned. A region derived here is cached as a `scene:*` channel keyed by TARGET ONLY, so a later call for the same target loads it by name; pass `refresh:true` to force a fresh derive after an edit that changes what the region means, and note that narrowing a call with `label`/`instance`/`composition_context` always derives (it neither reads nor writes that shared channel). The structural floor (coherence, horizon alignment) is never tuned; for an artistic/non-standard shot pass `composition_context` (e.g. profile:big_sky) to relax the compositional priors so a legitimately large sky is not rejected. For target=subject with several present, pass `label` and/or `instance`. Build/inspect with ps_read_scene first; verify with ps_get_selection_preview (the red-overlay is the human/agent oversight view). Prefer this over a rectangle for any real-world region.

Input parameters:

- `composition_context` (object): Optional: tune the confidence gate from what you SEE in the preview, so an artistic shot is not rejected for breaking norms. The structural floor (coherence / horizon alignment) is never tuned; only…
- `instance` (integer): For target=subject only: 0-based index counting left-to-right among matching subjects (0 = leftmost). Omit to pick the main/largest.
- `label` (string): For target=subject only: a COCO class ('person', 'dog', 'car', …) to pick instead of the largest subject. Ignored for other targets.
- `max_dimension` (number): Long-edge px of the perception export when a fresh pass runs.
- `refresh` (boolean): Force a fresh perception pass before resolving (default false uses the cached scene model for the current document state).
- `target` (string, required): What to select by NAME (no coordinates): 'sky' (threshold white split), 'above_horizon' (everything above the horizon line), 'ground' / 'foliage' (posterize-region blob), 'subject' (the main detected…

Output parameters:

- `confidence` (number)
- `detail` (object)
- `doc` (object)
- `method` (string)
- `op` (string)
- `passed` (boolean)
- `reasons` (array)
- `selection_info` (object|null)
- `target` (string)

### `ps_sequence` (~559 tokens)

Run an ordered list of tool calls against the current document in ONE round trip. WHEN TO REACH FOR THIS: several dependent steps you already know you want (e.g. select → adjust → merge, or a repeated resize/export pass) where you do not need to look at the result between them — each step is dispatched the same way an ordinary call is and sees the document exactly as the previous step left it. Not for exploratory work: if the next step depends on inspecting this one first, call the tools individually instead. Every step must name a tool that already exists in this edition (ps_sequence cannot call itself). An inline preview (image content) returned by a step is dropped unless that step is the LAST one in the sequence, since previews are most of a result's bytes and the point of batching calls is to stop paying for them on every intermediate step. Each step keeps its own time limit, exactly as it would if you called it on its own. The sequence's overall budget only decides whether to START another step, so it never cuts one off mid-run — a call can therefore finish after that ceiling by however long the in-flight step still needs, plus the undo and its verification reads when on_error='rollback'. With return='full', every step's complete result (not just the last one's) lands in the logged call payload.

Input parameters:

- `on_error` (string): stop: halt at the first failing step and return results so far. continue: record the failure and run every remaining step anyway. rollback: on the first failing step, undo back to the history state c…
- `return` (string): summary: one line per step plus the LAST step's full result. full: every step's full result — note this means every embedded payload (not just the last step's) lands in the logged call record. Either…
- `steps` (array, required): Ordered list of tool calls to run against the current document, 1 to 25 items.

Output parameters:

- `cap_exceeded` (boolean)
- `failed_step` (object|null): The first failing step, or the step skipped by the overall time budget. Null when every step succeeded.
- `final` (object): The last step's full CallToolResult (summary mode only).
- `on_error` (string)
- `ran_steps` (number): How many steps actually ran — excludes a step skipped by the time budget.
- `return` (string)
- `rollback_reason` (string): Set only when on_error="rollback" and rolled_back is false: history_evicted, undo_failed, cursor_moved_backward, or document_changed.
- `rolled_back` (boolean)
- `steps` (array): One entry per step run — carries `text` in summary mode, `result` in full mode.
- `total_steps` (number)

## Diagnostics

Captured diagnostic sections: Provenance, Dependencies. The full working is on the page: https://verifymcp.io/servers/editmamei-editmamei/editmamei#diagnostics

## Score history

- 2026-09-20: 88
- 2026-09-19: 87
- 2026-09-18: 61
- 2026-09-17: 86
- 2026-09-16: 86
- 2026-09-15: 85
- 2026-09-14: 85
- 2026-09-13: 88
- 2026-09-12: 87
- 2026-09-11: 87
- 2026-09-10: 87
- 2026-09-09: 86
- 2026-09-08: 86
- 2026-09-07: 71
- 2026-09-06: 85
- 2026-09-05: 85
- 2026-09-04: 84
- 2026-09-03: 84
- 2026-09-02: 83
- 2026-09-01: 83
- 2026-08-31: 82
- 2026-08-30: 82
- 2026-08-29: 67
- 2026-08-28: 81
- 2026-08-27: 81
- 2026-08-26: 80
- 2026-08-25: 78
- 2026-08-24: 78
- 2026-08-23: 77
- 2026-08-22: 78

## Common questions

### What is the io.github.editmamei/editmamei MCP server?

io.github.editmamei/editmamei is an MCP server listed in the public MCP registry as io.github.editmamei/editmamei. Photoshop MCP server: natural-language AI photo editing in desktop Photoshop. AI orchestration. This page covers its npm package (editmamei).

### Is the io.github.editmamei/editmamei MCP server safe to use?

io.github.editmamei/editmamei scores 88 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 20 September 2026. It declares no install or post-install scripts. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the io.github.editmamei/editmamei MCP server expose?

io.github.editmamei/editmamei exposes 62 tools: ps_ping, ps_list_capabilities, ps_create_document, ps_document, ps_close_document, and 57 more. Their descriptions and schemas cost roughly 28,680 tokens of context every time the server is loaded.

### Is the io.github.editmamei/editmamei MCP server still maintained?

io.github.editmamei/editmamei is still listed as active in the MCP registry. We last reached this channel on 20 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

### What licence is the io.github.editmamei/editmamei MCP server under?

io.github.editmamei/editmamei declares the FSL-1.1-MIT licence, which is not on the OSI-approved list. Read the terms before using it at work, and note this covers the source only, not the cost of any service it calls.

## Links

- npm package: https://www.npmjs.com/package/editmamei
- Socket report: https://socket.dev/npm/package/editmamei
- Repository: https://github.com/editmamei/editmamei
- Website: https://editmamei.com/
- Changelog RSS feed: https://verifymcp.io/servers/editmamei-editmamei/editmamei.xml
- Changelog JSON feed: https://verifymcp.io/servers/editmamei-editmamei/editmamei.json
- HTML version of this page: https://verifymcp.io/servers/editmamei-editmamei/editmamei
