harnessgg-blender

Published v0.3.0

CLI harness for AI agents to automate Blender 3D. Create scenes, manipulate objects, configure cameras and lights, apply materials, and render stills or animations with structured JSON output via a local bridge.

pip install harnessgg-blender

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

Prerequisite

Blender must be installed and accessible on your PATH. The harness communicates with Blender through a local bridge process on port 41749. Python 3.10+ is required.

terminal
$ harnessgg-blender 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-blender bridge start


# 2. Verify stability
$ harnessgg-blender bridge status
$ harnessgg-blender bridge verify --iterations 25


# 3. Create a new project and inspect it
$ harnessgg-blender file new scene.blend --overwrite
$ harnessgg-blender file inspect scene.blend
{"ok":true,"protocolVersion":"1.0","command":"file inspect","data":{"objects":[],"materials":[],"cameras":[]}}


# 4. Add objects and a material
$ harnessgg-blender object add scene.blend CUBE --name "Body" --location-json "[0,0,0]"
$ harnessgg-blender material create scene.blend PBR --base-color "#4a7aaa" --roughness 0.4
$ harnessgg-blender material assign scene.blend Body PBR


# 5. Add a camera and light, then render
$ harnessgg-blender camera add scene.blend --name "MainCam" --location-json "[5,5,3]"
$ harnessgg-blender camera set-active scene.blend MainCam
$ harnessgg-blender light add scene.blend SUN --name "Key" --energy 5.0
$ harnessgg-blender render still scene.blend out.png --engine CYCLES --samples 128
{"ok":true,"protocolVersion":"1.0","command":"render still","data":{"jobId":"job_r1","status":"queued"}}
$ harnessgg-blender render status job_r1

Schema examples

Each command returns one JSON object. Check ok first, then inspect data or error.

success
{"ok":true,"protocolVersion":"1.0","command":"render still","data":{"jobId":"job_r1","status":"queued"}}
error
{"ok":false,"protocolVersion":"1.0","command":"material assign","error":{"code":"NOT_FOUND","message":"Object \"Body\" not found","retryable":false}}

Bridge commands

The bridge must be running on port 41749 before any file, object, render, or other commands. It binds to 127.0.0.1 only by default.

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

Start the local bridge server on port 41749. Must be running before any file, object, render, or other commands.

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

Run the bridge in the foreground without daemonizing. Useful for debugging or containerized environments.

bridge stop
harnessgg-blender bridge stop

Shut down the running bridge server.

bridge status
harnessgg-blender bridge status

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

bridge verify
harnessgg-blender bridge verify [--iterations 25] [--max-failures 0]

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

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

System commands

Environment and capability checks. These do not require a project file.

version
harnessgg-blender version

Print the installed harnessgg-blender version. Does not require a running bridge.

doctor
harnessgg-blender doctor [--include-render]

Check that Blender is installed, the bridge is reachable, and the environment is healthy.

FlagRequiredDescription
--include-render no Also verify that rendering is functional
actions
harnessgg-blender actions

List all available commands and subcommand groups supported by the bridge.

File commands

Create, copy, inspect, and version-control .blend project files. Run file validate before renders and after destructive changes.

file new
harnessgg-blender file new <output.blend> [--overwrite]

Create a new empty Blender project file at the given path.

FlagRequiredDescription
--overwrite no Replace an existing file at the target path
file copy
harnessgg-blender file copy <source> <target> [--overwrite]

Duplicate a .blend file to a new location.

FlagRequiredDescription
--overwrite no Replace an existing file at the target path
file inspect
harnessgg-blender file inspect <project.blend>

Return a structured summary of the project: objects, materials, cameras, lights, and scene settings.

file validate
harnessgg-blender file validate <project.blend>

Validate the project structure. Run before renders and after destructive edits.

file diff
harnessgg-blender file diff <source> <target>

Compare two .blend files and report structural differences.

file snapshot
harnessgg-blender file snapshot <project> <description>

Save a named checkpoint of the project. Use before risky edits; restore with file undo.

file undo / file redo
harnessgg-blender file undo <project> [--snapshot-id <id>]
harnessgg-blender file redo <project>

Undo the last edit or redo it. Pass --snapshot-id to jump to a specific named checkpoint.

FlagRequiredDescription
--snapshot-id no Target snapshot identifier (undo only)

Object commands

Add, transform, and manage scene objects. Pass JSON arrays for location, rotation, and scale.

object list
harnessgg-blender object list <project> [--type MESH|CAMERA|LIGHT]

List all objects in the scene, optionally filtered by type.

FlagRequiredDescription
--type no Filter: MESH, CAMERA, or LIGHT
object add
harnessgg-blender object add <project> CUBE|SPHERE|CYLINDER|PLANE|CONE|TORUS [--name <s>] [--location-json <json>] [--rotation-json <json>] [--scale-json <json>] [--output <path>]

Add a primitive mesh object to the scene.

FlagRequiredDescription
--name no Object name (auto-generated if omitted)
--location-json no XYZ position as JSON array, e.g. "[0,0,1]"
--rotation-json no XYZ euler rotation in radians as JSON array
--scale-json no XYZ scale as JSON array
--output no Write the modified project to this path instead of in-place
object transform
harnessgg-blender object transform <project> <name> [--location-json <json>] [--rotation-json <json>] [--scale-json <json>] [--output <path>]

Set the location, rotation, or scale of a named object.

FlagRequiredDescription
--location-json no New XYZ position
--rotation-json no New XYZ rotation in radians
--scale-json no New XYZ scale
--output no Write to a different output path
object delete
harnessgg-blender object delete <project> <name> [--output <path>]

Remove a named object from the scene.

FlagRequiredDescription
--output no Write to a different output path
object duplicate
harnessgg-blender object duplicate <project> <name> [--new-name <s>] [--output <path>]

Duplicate an object in the scene.

FlagRequiredDescription
--new-name no Name for the duplicated object
--output no Write to a different output path
object rename
harnessgg-blender object rename <project> <name> <new-name> [--output <path>]

Rename an object.

FlagRequiredDescription
--output no Write to a different output path
object parent / object unparent
harnessgg-blender object parent <project> <child> <parent> [--output <path>]
harnessgg-blender object unparent <project> <child> [--output <path>]

Set or clear the parent of an object.

FlagRequiredDescription
--output no Write to a different output path
object shade-smooth / object shade-flat
harnessgg-blender object shade-smooth <project> <name> [--output <path>]
harnessgg-blender object shade-flat <project> <name> [--output <path>]

Set smooth or flat shading on a mesh object.

FlagRequiredDescription
--output no Write to a different output path

Camera and light commands

Configure cameras (lens, DoF, active camera) and add or adjust lights. Always call camera set-active before rendering.

camera list
harnessgg-blender camera list <project>

List all cameras in the scene.

camera add
harnessgg-blender camera add <project> [--name <s>] [--location-json <json>] [--rotation-json <json>] [--output <path>]

Add a new camera to the scene.

FlagRequiredDescription
--name no Camera name
--location-json no XYZ position as JSON array
--rotation-json no XYZ rotation in radians as JSON array
--output no Write to a different output path
camera set-active
harnessgg-blender camera set-active <project> <name> [--output <path>]

Set the named camera as the active render camera.

FlagRequiredDescription
--output no Write to a different output path
camera set-lens
harnessgg-blender camera set-lens <project> <name> <lens_mm> [--output <path>]

Set the focal length of a camera in millimetres.

FlagRequiredDescription
--output no Write to a different output path
camera set-dof
harnessgg-blender camera set-dof <project> <name> [--use-dof] [--focus-distance <f>] [--aperture-fstop <f>] [--focus-object <s>] [--output <path>]

Configure depth-of-field for a camera.

FlagRequiredDescription
--use-dof no Enable depth-of-field
--focus-distance no Focus distance in metres
--aperture-fstop no Aperture f-stop value
--focus-object no Track focus to a named object
--output no Write to a different output path
light add
harnessgg-blender light add <project> POINT|SUN|SPOT|AREA [--name <s>] [--energy 1000.0] [--color <hex>] [--location-json <json>] [--output <path>]

Add a light of the specified type to the scene.

FlagRequiredDescription
--name no Light name
--energy no Light power in watts (default: 1000.0)
--color no Light colour as hex, e.g. "#ffffff"
--location-json no XYZ position as JSON array
--output no Write to a different output path
light list
harnessgg-blender light list <project>

List all lights in the scene.

light set-energy
harnessgg-blender light set-energy <project> <name> <energy> [--output <path>]

Set the power of a light in watts.

FlagRequiredDescription
--output no Write to a different output path
light set-color
harnessgg-blender light set-color <project> <name> <hex> [--output <path>]

Set the colour of a light using a hex string.

FlagRequiredDescription
--output no Write to a different output path

Material and modifier commands

Create Principled BSDF materials and manage object modifiers. Assign materials after creating them.

material list
harnessgg-blender material list <project>

List all materials defined in the project.

material create
harnessgg-blender material create <project> <name> [--base-color <hex>] [--metallic <f>] [--roughness <f>] [--output <path>]

Create a new Principled BSDF material.

FlagRequiredDescription
--base-color no Base colour as hex, e.g. "#ffffff"
--metallic no Metallic value 0.0 to 1.0
--roughness no Roughness value 0.0 to 1.0
--output no Write to a different output path
material assign
harnessgg-blender material assign <project> <object> <material> [--output <path>]

Assign a material to a named object.

FlagRequiredDescription
--output no Write to a different output path
material set-base-color
harnessgg-blender material set-base-color <project> <name> <hex> [--output <path>]

Update the base colour of an existing material.

FlagRequiredDescription
--output no Write to a different output path
material set-metallic
harnessgg-blender material set-metallic <project> <name> <value> [--output <path>]

Set the metallic value (0.0 to 1.0) of a material.

FlagRequiredDescription
--output no Write to a different output path
material set-roughness
harnessgg-blender material set-roughness <project> <name> <value> [--output <path>]

Set the roughness value (0.0 to 1.0) of a material.

FlagRequiredDescription
--output no Write to a different output path
modifier list
harnessgg-blender modifier list <project> <object>

List all modifiers on a named object.

modifier add
harnessgg-blender modifier add <project> <object> <type> [--modifier-name <s>] [--output <path>]

Add a modifier of the given type to an object (e.g. SUBSURF, SOLIDIFY, ARRAY).

FlagRequiredDescription
--modifier-name no Name for the new modifier
--output no Write to a different output path
modifier remove
harnessgg-blender modifier remove <project> <object> <name> [--output <path>]

Remove a named modifier from an object.

FlagRequiredDescription
--output no Write to a different output path
modifier apply
harnessgg-blender modifier apply <project> <object> <name> [--output <path>]

Apply a modifier permanently, baking its effect into the mesh.

FlagRequiredDescription
--output no Write to a different output path

Import and export

Import external assets into a project or export the scene. Both commands have a 300s timeout. Supported formats: glTF, FBX, OBJ, USD.

import gltf|fbx|obj|usd
harnessgg-blender import gltf|fbx|obj|usd <project> <source> [--output <path>]

Import a mesh or scene file into the project. Supports glTF, FBX, OBJ, and USD formats. Timeout: 300s.

FlagRequiredDescription
--output no Write the modified project to this path
export gltf|fbx|obj|usd
harnessgg-blender export gltf|fbx|obj|usd <project> <target>

Export the scene or selected objects to a file. Supports glTF, FBX, OBJ, and USD formats. Timeout: 300s.

Render commands

Render calls are long-running and return a job_id immediately. Poll render status until the job completes or fails. Still timeout: 600s. Animation timeout: 1800s.

render still
harnessgg-blender render still <project> <output.png> [--engine BLENDER_EEVEE|CYCLES] [--samples 64] [--resolution-x 1920] [--resolution-y 1080] [--camera <name>]

Render a single frame to a PNG file. Returns a job_id immediately. Poll render status for progress. Timeout: 600s.

FlagRequiredDescription
--engine no BLENDER_EEVEE or CYCLES (default: BLENDER_EEVEE)
--samples no Sample count (default: 64)
--resolution-x no Output width in pixels (default: 1920)
--resolution-y no Output height in pixels (default: 1080)
--camera no Camera name to render from
render animation
harnessgg-blender render animation <project> <output_dir> [--engine BLENDER_EEVEE|CYCLES] [--frame-start 1] [--frame-end 250] [--fps 24] [--format PNG|JPEG|FFMPEG]

Render an animation sequence to a directory. Returns a job_id. Timeout: 1800s.

FlagRequiredDescription
--engine no BLENDER_EEVEE or CYCLES
--frame-start no First frame to render (default: 1)
--frame-end no Last frame to render (default: 250)
--fps no Frames per second (default: 24)
--format no Output format: PNG, JPEG, or FFMPEG
render status
harnessgg-blender render status <job_id>

Poll the status and progress of an active or completed render job.

render cancel
harnessgg-blender render cancel <job_id>

Cancel a queued or running render job.

Full command list

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

commands
# Bridge
$ harnessgg-blender bridge start [--host 127.0.0.1] [--port 41749]
$ harnessgg-blender bridge serve [--host 127.0.0.1] [--port 41749]
$ harnessgg-blender bridge status
$ harnessgg-blender bridge stop
$ harnessgg-blender bridge verify [--iterations 25] [--max-failures 0]
$ harnessgg-blender bridge run-python  [--project ] [--params-json ] [--timeout-seconds ]

# System
$ harnessgg-blender actions
$ harnessgg-blender capabilities
$ harnessgg-blender doctor [--include-render/--no-include-render]
$ harnessgg-blender version
$ harnessgg-blender run-plan  [--rollback-on-fail/--no-rollback-on-fail] [--dry-run]

# File
$ harnessgg-blender file new  [--overwrite]
$ harnessgg-blender file copy   [--overwrite]
$ harnessgg-blender file inspect 
$ harnessgg-blender file validate 
$ harnessgg-blender file diff  
$ harnessgg-blender file snapshot  
$ harnessgg-blender file undo  [--snapshot-id ]
$ harnessgg-blender file redo 

# Object
$ harnessgg-blender object list  [--type MESH|CAMERA|LIGHT]
$ harnessgg-blender object add   [--name ] [--location-json ] [--rotation-json ] [--scale-json ] [--output ] [--list-primitives]
$ harnessgg-blender object transform   [--location-json ] [--rotation-json ] [--scale-json ] [--output ]
$ harnessgg-blender object delete   [--output ]
$ harnessgg-blender object delete-all  [--output ]
$ harnessgg-blender object material-list  
$ harnessgg-blender object duplicate   [--new-name ] [--output ]
$ harnessgg-blender object rename    [--output ]
$ harnessgg-blender object parent    [--output ]
$ harnessgg-blender object unparent   [--output ]
$ harnessgg-blender object apply-transform   [--apply-location/--no-apply-location] [--apply-rotation/--no-apply-rotation] [--apply-scale/--no-apply-scale] [--output ]
$ harnessgg-blender object origin-set   [--origin-type ORIGIN_GEOMETRY|ORIGIN_CURSOR|ORIGIN_CENTER_OF_MASS|ORIGIN_CENTER_OF_VOLUME] [--output ]
$ harnessgg-blender object shade-smooth   [--output ]
$ harnessgg-blender object shade-flat   [--output ]
$ harnessgg-blender object transform-many   [--location-json ] [--rotation-json ] [--scale-json ] [--output ]
$ harnessgg-blender object boolean-union    [--apply/--no-apply] [--delete-with/--keep-with] [--output ]
$ harnessgg-blender object boolean-difference    [--apply/--no-apply] [--delete-with/--keep-with] [--output ]
$ harnessgg-blender object boolean-intersect    [--apply/--no-apply] [--delete-with/--keep-with] [--output ]
$ harnessgg-blender object join   [--output ]
$ harnessgg-blender object convert-mesh   [--output ]
$ harnessgg-blender object shrinkwrap    [--wrap-method ] [--offset ] [--apply/--no-apply] [--output ]
$ harnessgg-blender object data-transfer    [--data-domain LOOP|VERTEX|EDGE|POLY] [--data-type ] [--apply/--no-apply] [--output ]
$ harnessgg-blender object group-create    [--location-json ] [--output ]
$ harnessgg-blender object parent-many    [--output ]

# Camera
$ harnessgg-blender camera add  [--name Camera] [--location-json ] [--rotation-json ] [--output ]
$ harnessgg-blender camera set-active   [--output ]
$ harnessgg-blender camera list 
$ harnessgg-blender camera transform   [--location-json ] [--rotation-json ] [--scale-json ] [--output ]
$ harnessgg-blender camera set-lens    [--output ]
$ harnessgg-blender camera set-dof   [--use-dof/--no-use-dof] [--focus-distance ] [--aperture-fstop ] [--focus-object ] [--output ]
$ harnessgg-blender camera look-at   [--target-object ] [--target-location-json ] [--output ]
$ harnessgg-blender camera rig-product-shot   [--camera-name ] [--distance ] [--height ] [--lens ] [--output ]

# Light
$ harnessgg-blender light add   [--name ] [--energy ] [--color ] [--location-json ] [--output ]
$ harnessgg-blender light list 
$ harnessgg-blender light set-energy    [--output ]
$ harnessgg-blender light set-color    [--output ]
$ harnessgg-blender light rig-three-point  [--target-object ] [--output ]

# Material
$ harnessgg-blender material list 
$ harnessgg-blender material create   [--base-color ] [--metallic ] [--roughness ] [--output ]
$ harnessgg-blender material assign    [--output ]
$ harnessgg-blender material assign-many    [--output ]
$ harnessgg-blender material set-base-color    [--output ]
$ harnessgg-blender material set-metallic    [--output ]
$ harnessgg-blender material set-roughness    [--output ]
$ harnessgg-blender material set-node-input      [--output ]

# Modifier
$ harnessgg-blender modifier list  
$ harnessgg-blender modifier add    [--modifier-name ] [--output ]
$ harnessgg-blender modifier remove    [--output ]
$ harnessgg-blender modifier apply    [--output ]
$ harnessgg-blender modifier set      [--output ]
$ harnessgg-blender geometry-nodes attach   [--modifier-name ] [--output ]
$ harnessgg-blender geometry-nodes set-input     [--modifier-name ] [--output ]

# Mesh
$ harnessgg-blender mesh smooth   [--iterations ] [--factor ] [--output ]
$ harnessgg-blender mesh subdivide   [--cuts ] [--output ]
$ harnessgg-blender mesh select-verts    [--replace/--add] [--output ]
$ harnessgg-blender mesh clear-selection   [--output ]
$ harnessgg-blender mesh transform-selected   [--location-json ] [--rotation-json ] [--scale-json ] [--output ]
$ harnessgg-blender mesh proportional-edit   [--location-json ] [--scale-json ] [--falloff ] [--radius ] [--output ]
$ harnessgg-blender mesh extrude-region   [--offset-json ] [--output ]
$ harnessgg-blender mesh bevel-verts   [--amount ] [--segments ] [--output ]
$ harnessgg-blender mesh merge-by-distance   [--distance ] [--output ]
$ harnessgg-blender mesh loop-cut    [--cuts ] [--output ]
$ harnessgg-blender mesh slide-loop    [--factor ] [--output ]
$ harnessgg-blender mesh bisect   [--plane-co-json ] [--plane-no-json ] [--clear-inner/--keep-inner] [--clear-outer/--keep-outer] [--use-fill/--no-fill] [--output ]
$ harnessgg-blender mesh clean   [--merge-distance ] [--dissolve-angle ] [--output ]

# Lattice
$ harnessgg-blender lattice add  [--name Lattice] [--location-json ] [--scale-json ] [--points-u ] [--points-v ] [--points-w ] [--output ]
$ harnessgg-blender lattice bind    [--modifier-name Lattice] [--output ]
$ harnessgg-blender lattice set-point      [--location-json ] [--delta/--absolute] [--output ]

# Curve
$ harnessgg-blender curve add-bezier   [--name BezierCurve] [--output ]
$ harnessgg-blender curve set-handle     [--handle left|right] [--handle-type ] [--output ]
$ harnessgg-blender curve to-mesh   [--output ]

# Scene utilities
$ harnessgg-blender scene add-reference-image   [--name ] [--location-json ] [--scale-json ] [--output ]
$ harnessgg-blender scene set-orthographic   [--ortho-scale ] [--output ]
$ harnessgg-blender scene set-world-background  [--color ] [--strength ] [--output ]
$ harnessgg-blender scene set-color-management  [--view-transform ] [--look ] [--exposure ] [--gamma ] [--output ]

# Analyze
$ harnessgg-blender analyze silhouette-diff    [--threshold ]

# Timeline and animation
$ harnessgg-blender timeline set-frame-range    [--output ]
$ harnessgg-blender timeline set-current-frame   [--output ]
$ harnessgg-blender keyframe insert     [--value ] [--array-index ] [--output ]
$ harnessgg-blender keyframe delete     [--array-index ] [--output ]
$ harnessgg-blender fcurve list  [--object-name ]
$ harnessgg-blender fcurve set-interpolation     [--array-index ] [--output ]
$ harnessgg-blender nla track-add    [--output ]
$ harnessgg-blender action list 
$ harnessgg-blender action push-down   [--output ]
$ harnessgg-blender constraint add    [--constraint-name ] [--target ] [--output ]

# Import, export, and assets
$ harnessgg-blender import gltf   [--output ]
$ harnessgg-blender import fbx   [--output ]
$ harnessgg-blender import obj   [--output ]
$ harnessgg-blender import usd   [--output ]
$ harnessgg-blender export gltf  
$ harnessgg-blender export fbx  
$ harnessgg-blender export obj  
$ harnessgg-blender export usd  
$ harnessgg-blender asset list 
$ harnessgg-blender asset relink-missing   [--output ]
$ harnessgg-blender pack resources  [--output ]
$ harnessgg-blender unpack resources  [--output ]

# Render
$ harnessgg-blender render still   [--engine BLENDER_EEVEE|CYCLES|BLENDER_WORKBENCH] [--samples ] [--resolution-x ] [--resolution-y ] [--camera ]
$ harnessgg-blender render animation   [--engine BLENDER_EEVEE|CYCLES|BLENDER_WORKBENCH] [--frame-start ] [--frame-end ] [--fps ] [--format PNG|JPEG|OPEN_EXR|FFMPEG]
$ harnessgg-blender render status 
$ harnessgg-blender render cancel     

Response shape

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

Success

{
  "ok": true,
  "protocolVersion": "1.0",
  "command": "object add",
  "data": { "name": "Body" }
}

Error

{
  "ok": false,
  "protocolVersion": "1.0",
  "command": "object add",
  "error": {
    "code": "INVALID_INPUT",
    "message": "Unknown primitive 'TORUS2'",
    "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).
INVALID_INPUT 4 no Bad or missing arguments. Fix the command before retrying.
VALIDATION_FAILED 3 no Project structure is invalid. Run file validate and fix reported issues first.
NOT_FOUND 2 no Referenced object, material, or file does not exist. Check names and paths.
ERROR 1 no Unexpected error. Retry once; if it persists, file a bug report.

Submit feedback

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

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