harnessgg-gimp

Published v0.2.0

CLI harness for AI agents to automate GIMP image editing. Resize, crop, adjust colours, apply filters, manage layers, and export, all with structured JSON output via a local bridge.

pip install harnessgg-gimp

Agents can file bugs or feature requests with curl -X POST https://harness.gg/api/submit using "package":"gimp" in the JSON payload.

Prerequisite

GIMP must be installed. The harness uses a local bridge process on port 41749 to communicate with it. Python 3.10+ required.

terminal
$ harnessgg-gimp bridge start

Always call bridge status before editing commands. Retry only on BRIDGE_UNAVAILABLE (exit 5) with backoff 0.5s, 1s, 2s.

Quick flow

full agent session
# 1. Start the bridge
$ harnessgg-gimp bridge start


# 2. Inspect the image
$ harnessgg-gimp inspect photo.png
{"ok":true,"protocolVersion":"1.0","command":"inspect","data":{"width":3840,"height":2160,"layers":1}}


# 3. Resize it
$ harnessgg-gimp resize photo.png --width 1920 --height 1080 --output resized.png
{"ok":true,"protocolVersion":"1.0","command":"resize","data":{}}


# 4. Adjust brightness and contrast
$ harnessgg-gimp brightness-contrast resized.png --brightness 0.1 --contrast 0.2 --output adjusted.png
{"ok":true,"protocolVersion":"1.0","command":"brightness-contrast","data":{}}


# 5. Apply a gaussian blur
$ harnessgg-gimp gaussian-blur adjusted.png --radius-x 2.0 --radius-y 2.0 --output blurred.png
{"ok":true,"protocolVersion":"1.0","command":"gaussian-blur","data":{}}


# 6. Export as JPEG
$ harnessgg-gimp export blurred.png final.jpg
{"ok":true,"protocolVersion":"1.0","command":"export","data":{"output":"final.jpg"}}

Schema examples

Each command returns one JSON object. Use ok and error.code for branching.

success
{"ok":true,"protocolVersion":"1.0","command":"resize","data":{"output":"resized.png"}}
error
{"ok":false,"protocolVersion":"1.0","command":"open","error":{"code":"NOT_FOUND","message":"File not found","retryable":false}}

Bridge commands

The bridge must be running before any image editing call. It binds to 127.0.0.1:41749 by default.

bridge start
harnessgg-gimp bridge start [--host 127.0.0.1] [--port 41749]

Start the local bridge server on port 41749. Must be running before any image editing commands.

FlagRequiredDescription
--host no Bind address (default: 127.0.0.1)
--port no Port (default: 41749)
bridge serve
harnessgg-gimp bridge serve

Run the bridge in the foreground (blocking). Useful for container environments.

bridge stop
harnessgg-gimp bridge stop

Shut down the running bridge server.

bridge status
harnessgg-gimp bridge status

Check whether the bridge is reachable and healthy. Run before any mutating commands.

bridge verify
harnessgg-gimp bridge verify [--iterations 10] [--max-failures 0]

Run a stability check against the bridge. Recommended before long editing sessions.

FlagRequiredDescription
--iterations no Number of health pings (default: 10)
--max-failures no Allowed failures before abort (default: 0)

System commands

Utility commands for checking the installation. version does not require the bridge.

version
harnessgg-gimp version

Print the package version. Does not require the bridge to be running.

doctor
harnessgg-gimp doctor

Check the installation environment: GIMP availability, bridge connectivity, and Python version.

actions
harnessgg-gimp actions

List all available commands with their synopses. Useful for agent discovery.

File commands

Commands operate on image file paths. Use --output to save to a different path; the default behaviour is to overwrite the input file.

open
harnessgg-gimp open <image>

Open an image file through the bridge. Use before commands that require an open document context.

save
harnessgg-gimp save <image> <output>

Save the image to a file path. Writes in the format inferred from the output extension.

export
harnessgg-gimp export <image> <output>

Export the image, inferring format from the output file extension. Supported extensions: .jpg, .png, .webp, .xcf.

clone-project
harnessgg-gimp clone-project <source> <target> [--overwrite]

Copy an image file to a new path. Use to create a working copy before destructive edits.

FlagRequiredDescription
--overwrite no Replace target if it already exists
inspect
harnessgg-gimp inspect <image>

Return a structured summary of the image: dimensions, colour mode, layer count, and layer names.

validate
harnessgg-gimp validate <image>

Check that the image file is readable and structurally valid. Run before a batch pipeline.

diff
harnessgg-gimp diff <source> <target>

Compare two image files and return a pixel-level difference summary.

snapshot
harnessgg-gimp snapshot <image> <description>

Save a named checkpoint of the image state. Use before risky edits; restore with undo.

undo
harnessgg-gimp undo <image>

Undo the last edit applied to the image.

redo
harnessgg-gimp redo <image>

Redo the last undone edit.

Transform commands

Geometric transformations on the full image canvas. All accept --output to preserve the original.

resize
harnessgg-gimp resize <image> --width <int> --height <int> [--output <path>]

Scale the image to the given dimensions. Overwrites the input file unless --output is specified.

FlagRequiredDescription
--width yes Target width in pixels
--height yes Target height in pixels
--output no Save result to a different file (default: overwrite input)
crop
harnessgg-gimp crop <image> --x <int> --y <int> --width <int> --height <int> [--output <path>]

Crop the image to the given rectangle.

FlagRequiredDescription
--x yes Left edge of the crop region in pixels
--y yes Top edge of the crop region in pixels
--width yes Crop width in pixels
--height yes Crop height in pixels
--output no Output file path (default: overwrite input)
rotate
harnessgg-gimp rotate <image> --degrees 90|180|270 [--output <path>]

Rotate the image by a fixed angle. Only 90, 180, and 270 degree values are accepted.

FlagRequiredDescription
--degrees yes 90, 180, or 270
--output no Output file path (default: overwrite input)
flip
harnessgg-gimp flip <image> --axis horizontal|vertical [--output <path>]

Flip the image along the horizontal or vertical axis.

FlagRequiredDescription
--axis yes horizontal or vertical
--output no Output file path (default: overwrite input)
canvas-size
harnessgg-gimp canvas-size <image> --width <int> --height <int> [--offset-x <int>] [--offset-y <int>] [--output <path>]

Resize the canvas without scaling the image content. Use offset flags to control where the existing content is positioned on the new canvas.

FlagRequiredDescription
--width yes New canvas width in pixels
--height yes New canvas height in pixels
--offset-x no X offset of existing content on the new canvas
--offset-y no Y offset of existing content on the new canvas
--output no Output file path (default: overwrite input)

Color adjustments

Colour correction commands. Use --layer-index to target a specific layer (default: 0).

brightness-contrast
harnessgg-gimp brightness-contrast <image> [--brightness <f>] [--contrast <f>] [--layer-index <int>] [--output <path>]

Adjust brightness and contrast on a layer. Values are floating-point offsets.

FlagRequiredDescription
--brightness no Brightness adjustment
--contrast no Contrast adjustment
--layer-index no Target layer (default: 0)
--output no Output file path (default: overwrite input)
levels
harnessgg-gimp levels <image> [--black <f>] [--white <f>] [--gamma <f>] [--layer-index <int>] [--output <path>]

Set input levels for black point, white point, and gamma on a layer.

FlagRequiredDescription
--black no Black input level
--white no White input level
--gamma no Gamma correction value
--layer-index no Target layer (default: 0)
--output no Output file path (default: overwrite input)
curves
harnessgg-gimp curves <image> --points-json <json> [--channel value|red|green|blue|alpha] [--layer-index <int>] [--output <path>]

Apply a curves adjustment using control points provided as a JSON array. Use --channel to target a specific channel.

FlagRequiredDescription
--points-json yes JSON array of curve control points
--channel no value, red, green, blue, or alpha (default: value)
--layer-index no Target layer (default: 0)
--output no Output file path (default: overwrite input)
color-balance
harnessgg-gimp color-balance <image> [--cyan-red <f>] [--magenta-green <f>] [--yellow-blue <f>] [--transfer-mode MIDTONES] [--layer-index <int>] [--output <path>]

Shift the colour balance of a layer across shadow, midtone, and highlight ranges.

FlagRequiredDescription
--cyan-red no Cyan-to-red shift
--magenta-green no Magenta-to-green shift
--yellow-blue no Yellow-to-blue shift
--transfer-mode no Tonal range: SHADOWS, MIDTONES, or HIGHLIGHTS (default: MIDTONES)
--layer-index no Target layer (default: 0)
--output no Output file path (default: overwrite input)
hue-saturation
harnessgg-gimp hue-saturation <image> [--hue <f>] [--saturation <f>] [--lightness <f>] [--layer-index <int>] [--output <path>]

Adjust hue, saturation, and lightness on a layer.

FlagRequiredDescription
--hue no Hue rotation in degrees
--saturation no Saturation adjustment
--lightness no Lightness adjustment
--layer-index no Target layer (default: 0)
--output no Output file path (default: overwrite input)
color-temperature
harnessgg-gimp color-temperature <image> --temperature <f> [--layer-index <int>] [--output <path>]

Shift the colour temperature of a layer. Positive values are warmer, negative values are cooler.

FlagRequiredDescription
--temperature yes Temperature shift value
--layer-index no Target layer (default: 0)
--output no Output file path (default: overwrite input)
invert
harnessgg-gimp invert <image> [--layer-index <int>] [--output <path>]

Invert the colours of a layer.

FlagRequiredDescription
--layer-index no Target layer (default: 0)
--output no Output file path (default: overwrite input)
desaturate
harnessgg-gimp desaturate <image> [--mode luma|average|lightness] [--layer-index <int>] [--output <path>]

Convert a layer to greyscale using the specified desaturation algorithm.

FlagRequiredDescription
--mode no luma, average, or lightness (default: luma)
--layer-index no Target layer (default: 0)
--output no Output file path (default: overwrite input)

Filters

Convolution and noise filters. All operate on a single layer and accept --output.

blur
harnessgg-gimp blur <image> [--radius 4.0] [--layer-index <int>] [--output <path>]

Apply a simple blur filter to a layer.

FlagRequiredDescription
--radius no Blur radius (default: 4.0)
--layer-index no Target layer (default: 0)
--output no Output file path (default: overwrite input)
gaussian-blur
harnessgg-gimp gaussian-blur <image> [--radius-x 4.0] [--radius-y 4.0] [--layer-index <int>] [--output <path>]

Apply a Gaussian blur with independent horizontal and vertical radii.

FlagRequiredDescription
--radius-x no Horizontal blur radius (default: 4.0)
--radius-y no Vertical blur radius (default: 4.0)
--layer-index no Target layer (default: 0)
--output no Output file path (default: overwrite input)
sharpen
harnessgg-gimp sharpen <image> [--radius 2.0] [--amount 1.0] [--layer-index <int>] [--output <path>]

Apply a sharpen filter to a layer.

FlagRequiredDescription
--radius no Sharpen radius (default: 2.0)
--amount no Sharpen strength (default: 1.0)
--layer-index no Target layer (default: 0)
--output no Output file path (default: overwrite input)
unsharp-mask
harnessgg-gimp unsharp-mask <image> [--radius 2.0] [--amount 1.0] [--threshold 0.0] [--layer-index <int>] [--output <path>]

Apply an unsharp mask for controlled edge sharpening.

FlagRequiredDescription
--radius no Radius of the blur used in the mask (default: 2.0)
--amount no Sharpening strength (default: 1.0)
--threshold no Minimum difference to apply sharpening (default: 0.0)
--layer-index no Target layer (default: 0)
--output no Output file path (default: overwrite input)
noise-reduction
harnessgg-gimp noise-reduction <image> [--strength 3] [--layer-index <int>] [--output <path>]

Apply a noise reduction filter to a layer.

FlagRequiredDescription
--strength no Reduction strength 1-10 (default: 3)
--layer-index no Target layer (default: 0)
--output no Output file path (default: overwrite input)

Layer commands

Add, remove, reorder, and configure layers. Use layer-list to discover layer indices before targeting them.

layer-list
harnessgg-gimp layer-list <image>

List all layers in the image with their index, name, opacity, and blend mode.

layer-add
harnessgg-gimp layer-add <image> --name <s> [--position <int>] [--output <path>]

Add a new empty layer to the image.

FlagRequiredDescription
--name yes Name for the new layer
--position no Insert position in the layer stack (default: top)
--output no Output file path (default: overwrite input)
layer-remove
harnessgg-gimp layer-remove <image> --layer-index <int> [--output <path>]

Remove the layer at the given index.

FlagRequiredDescription
--layer-index yes Index of the layer to remove
--output no Output file path (default: overwrite input)
layer-rename
harnessgg-gimp layer-rename <image> --layer-index <int> --name <s> [--output <path>]

Rename a layer.

FlagRequiredDescription
--layer-index yes Index of the target layer
--name yes New name for the layer
--output no Output file path (default: overwrite input)
layer-opacity
harnessgg-gimp layer-opacity <image> --layer-index <int> --opacity <0-100> [--output <path>]

Set the opacity of a layer to a value between 0 (transparent) and 100 (fully opaque).

FlagRequiredDescription
--layer-index yes Index of the target layer
--opacity yes Opacity value from 0 to 100
--output no Output file path (default: overwrite input)
layer-blend-mode
harnessgg-gimp layer-blend-mode <image> --layer-index <int> --mode <s> [--output <path>]

Set the blend mode of a layer. Common modes: NORMAL, MULTIPLY, SCREEN, OVERLAY.

FlagRequiredDescription
--layer-index yes Index of the target layer
--mode yes Blend mode name: NORMAL, MULTIPLY, SCREEN, OVERLAY, etc.
--output no Output file path (default: overwrite input)
layer-duplicate
harnessgg-gimp layer-duplicate <image> --layer-index <int> [--position <int>] [--output <path>]

Duplicate a layer and insert the copy at the specified position.

FlagRequiredDescription
--layer-index yes Index of the layer to duplicate
--position no Stack position for the new copy (default: directly above source)
--output no Output file path (default: overwrite input)
layer-merge-down
harnessgg-gimp layer-merge-down <image> --layer-index <int> [--output <path>]

Merge the layer at the given index down onto the layer below it.

FlagRequiredDescription
--layer-index yes Index of the layer to merge down
--output no Output file path (default: overwrite input)
layer-reorder
harnessgg-gimp layer-reorder <image> --layer-index <int> --index <int> [--output <path>]

Move a layer to a new position in the layer stack.

FlagRequiredDescription
--layer-index yes Current index of the layer to move
--index yes Destination index in the layer stack
--output no Output file path (default: overwrite input)

Selection commands

Create and manipulate selections. Selections persist across commands until cleared with select-none.

select-all
harnessgg-gimp select-all <image> [--output <path>]

Select the entire canvas.

FlagRequiredDescription
--output no Output file path (default: overwrite input)
select-none
harnessgg-gimp select-none <image> [--output <path>]

Deselect the current selection.

FlagRequiredDescription
--output no Output file path (default: overwrite input)
invert-selection
harnessgg-gimp invert-selection <image> [--output <path>]

Invert the current selection so that the unselected area becomes selected.

FlagRequiredDescription
--output no Output file path (default: overwrite input)
feather-selection
harnessgg-gimp feather-selection <image> --radius <f> [--output <path>]

Feather the edges of the current selection by the given radius.

FlagRequiredDescription
--radius yes Feather radius in pixels
--output no Output file path (default: overwrite input)
select-rectangle
harnessgg-gimp select-rectangle <image> --x <int> --y <int> --width <int> --height <int> [--output <path>]

Create a rectangular selection.

FlagRequiredDescription
--x yes Left edge of the selection
--y yes Top edge of the selection
--width yes Width of the selection
--height yes Height of the selection
--output no Output file path (default: overwrite input)
select-ellipse
harnessgg-gimp select-ellipse <image> --x <int> --y <int> --width <int> --height <int> [--output <path>]

Create an elliptical selection bounded by the given rectangle.

FlagRequiredDescription
--x yes Left edge of the bounding rectangle
--y yes Top edge of the bounding rectangle
--width yes Bounding rectangle width
--height yes Bounding rectangle height
--output no Output file path (default: overwrite input)
add-layer-mask
harnessgg-gimp add-layer-mask <image> --layer-index <int> [--mode WHITE] [--output <path>]

Add a layer mask to the specified layer. The default mode WHITE creates a fully visible mask.

FlagRequiredDescription
--layer-index yes Index of the layer to mask
--mode no Mask initialisation mode (default: WHITE)
--output no Output file path (default: overwrite input)
apply-layer-mask
harnessgg-gimp apply-layer-mask <image> --layer-index <int> [--output <path>]

Apply and remove the layer mask, merging it permanently into the layer.

FlagRequiredDescription
--layer-index yes Index of the layer whose mask to apply
--output no Output file path (default: overwrite input)

Text commands

Add and modify text layers, and stroke active selections.

add-text
harnessgg-gimp add-text <image> --text <s> --x <int> --y <int> [--font Sans] [--size 36.0] [--color #ffffff] [--layer-index <int>] [--output <path>]

Add a text layer to the image at the given coordinates.

FlagRequiredDescription
--text yes Text content to render
--x yes X position of the text origin
--y yes Y position of the text origin
--font no Font family name (default: Sans)
--size no Font size in points (default: 36.0)
--color no Text colour as a hex code (default: #ffffff)
--layer-index no Target layer for the text (default: 0)
--output no Output file path (default: overwrite input)
update-text
harnessgg-gimp update-text <image> --layer-index <int> --text <s> [--output <path>]

Update the text content of an existing text layer.

FlagRequiredDescription
--layer-index yes Index of the text layer to update
--text yes New text content
--output no Output file path (default: overwrite input)
stroke-selection
harnessgg-gimp stroke-selection <image> --width <f> [--color #ffffff] [--layer-index <int>] [--output <path>]

Stroke the current selection boundary with the given width and colour.

FlagRequiredDescription
--width yes Stroke width in pixels
--color no Stroke colour as a hex code (default: #ffffff)
--layer-index no Target layer (default: 0)
--output no Output file path (default: overwrite input)

Full command list

Complete CLI surface from the package docs. Use this list for long-form planning or tool coverage audits.

commands
# Bridge
$ harnessgg-gimp bridge serve [--host ] [--port ]
$ harnessgg-gimp bridge start [--host ] [--port ]
$ harnessgg-gimp bridge stop
$ harnessgg-gimp bridge status
$ harnessgg-gimp bridge verify [--iterations ] [--max-failures ]
$ harnessgg-gimp bridge soak [--iterations ] [--action ] [--action-params-json ]

# System
$ harnessgg-gimp actions
$ harnessgg-gimp capabilities
$ harnessgg-gimp doctor [--verbose]
$ harnessgg-gimp version
$ harnessgg-gimp plan-edit   [--params-json ]

# Project and safety
$ harnessgg-gimp open 
$ harnessgg-gimp save  
$ harnessgg-gimp export  
$ harnessgg-gimp montage-grid --images-json  --rows  --cols  --tile-width  --tile-height  --output  [--gutter ] [--background ] [--fit-mode cover|contain]
$ harnessgg-gimp clone-project   [--overwrite]
$ harnessgg-gimp inspect 
$ harnessgg-gimp validate 
$ harnessgg-gimp diff  
$ harnessgg-gimp snapshot  
$ harnessgg-gimp undo 
$ harnessgg-gimp redo 

# Transform
$ harnessgg-gimp resize  --width  --height  [--output ]
$ harnessgg-gimp crop  --x  --y  --width  --height  [--output ]
$ harnessgg-gimp crop-center  --width  --height  [--output ]
$ harnessgg-gimp rotate  --degrees <90|180|270> [--output ]
$ harnessgg-gimp flip  --axis horizontal|vertical [--output ]
$ harnessgg-gimp canvas-size  --width  --height  [--offset-x ] [--offset-y ] [--output ]

# Tone and color
$ harnessgg-gimp brightness-contrast  [--brightness ] [--contrast ] [--layer-index ] [--output ]
$ harnessgg-gimp levels  [--black ] [--white ] [--gamma ] [--layer-index ] [--output ]
$ harnessgg-gimp curves  [--channel ] --points-json  [--layer-index ] [--output ]
$ harnessgg-gimp hue-saturation  [--hue ] [--saturation ] [--lightness ] [--layer-index ] [--output ]
$ harnessgg-gimp color-balance  [--cyan-red ] [--magenta-green ] [--yellow-blue ] [--transfer-mode ] [--layer-index ] [--output ]
$ harnessgg-gimp color-temperature  --temperature  [--layer-index ] [--output ]
$ harnessgg-gimp invert  [--layer-index ] [--output ]
$ harnessgg-gimp desaturate  [--mode ] [--layer-index ] [--output ]

# Filters
$ harnessgg-gimp blur  [--radius ] [--layer-index ] [--output ]
$ harnessgg-gimp gaussian-blur  [--radius-x ] [--radius-y ] [--layer-index ] [--output ]
$ harnessgg-gimp sharpen  [--radius ] [--amount ] [--layer-index ] [--output ]
$ harnessgg-gimp unsharp-mask  [--radius ] [--amount ] [--threshold ] [--layer-index ] [--output ]
$ harnessgg-gimp noise-reduction  [--strength ] [--layer-index ] [--output ]

# Layers
$ harnessgg-gimp layer-list 
$ harnessgg-gimp layer-add  --name  [--position ] [--output ]
$ harnessgg-gimp layer-remove  --layer-index  [--output ]
$ harnessgg-gimp layer-rename  --layer-index  --name  [--output ]
$ harnessgg-gimp layer-opacity  --layer-index  --opacity <0-100> [--output ]
$ harnessgg-gimp layer-blend-mode  --layer-index  --mode  [--output ]
$ harnessgg-gimp layer-duplicate  --layer-index  [--position ] [--output ]
$ harnessgg-gimp layer-merge-down  --layer-index  [--output ]
$ harnessgg-gimp layer-reorder  --layer-index  --index  [--output ]

# Selection and masks
$ harnessgg-gimp select-all  [--output ]
$ harnessgg-gimp select-none  [--output ]
$ harnessgg-gimp invert-selection  [--output ]
$ harnessgg-gimp feather-selection  --radius  [--output ]
$ harnessgg-gimp select-rectangle  --x  --y  --width  --height  [--output ]
$ harnessgg-gimp select-ellipse  --x  --y  --width  --height  [--output ]
$ harnessgg-gimp add-layer-mask  --layer-index  [--layer-id ] [--mode ] [--output ]
$ harnessgg-gimp apply-layer-mask  --layer-index  [--layer-id ] [--output ]

# Text and annotation
$ harnessgg-gimp add-text  --text  --x  --y  [--font ] [--size ] [--color ] [--output ]
$ harnessgg-gimp update-text  --layer-index  [--layer-id ] --text  [--output ]
$ harnessgg-gimp stroke-selection  --width  [--color ] [--layer-index ] [--output ]

# Macros and presets
$ harnessgg-gimp run-macro  --macro  [--params-json ]
$ harnessgg-gimp list-presets
$ harnessgg-gimp apply-preset  

Response shape

Every command emits exactly one JSON object to stdout. Check ok first.

Success

{
  "ok": true,
  "protocolVersion": "1.0",
  "command": "resize",
  "data": {}
}

Error

{
  "ok": false,
  "protocolVersion": "1.0",
  "command": "resize",
  "error": {
    "code": "NOT_FOUND",
    "message": "File 'photo.png' not found",
    "retryable": false
  }
}

Error codes

CodeExitRetryableAction
BRIDGE_UNAVAILABLE 5 yes Bridge not reachable. Run bridge start then retry with backoff 0.5s, 1s, 2s (max 3 retries). This is the only retryable exit code.
INVALID_INPUT 4 no Bad or missing arguments. Fix the command before retrying.
VALIDATION_FAILED 3 no Image or parameters failed validation. Inspect the image and fix issues first.
NOT_FOUND 2 no File path not found. Check that the image path exists and is readable.
ERROR 1 no General error. Check the error message and fix the cause before retrying.

Submit feedback

Agents can file bug reports and feature requests via POST /api/submit. Issues land on harnessgg/harness-gimp.

FieldRequiredValues
typeyes"bug" | "feature" | "question"
packageyes"gimp"
titleyesShort summary
bodyyesFull description
contextnoBridge version, OS, image details...
file a bug report
$ curl -X POST https://harness.gg/api/submit \
  -H "Content-Type: application/json" \
  -d '{"type":"bug","package":"gimp","title":"bridge fails on start","body":"Steps..."}'