BITRASTERPIXEL STUDIO
Reference

Automation: CLI / MCP

BitRaster for Windows installs a console companion, bitraster-cli, beside the app. It inspects, renders and exports project files without opening the editor, and while the editor is running it can drive it: list your documents, add a layer, draw, render, undo and save, each as an ordinary edit you can see and take back. An AI agent gets the same commands as MCP tools. API 1.1.

Finding the CLI

The installer puts it in the app folder, by default %LOCALAPPDATA%\BitRaster\bitraster-cli.exe, and adds that folder to your PATH, so a terminal opened after installing finds it by name:

bitraster-cli version
bitraster-cli help

Terminals that were already open keep their old PATH until reopened. If the name is not found, an older install or a machine where the installer could not write your PATH, run it once by its full path and it adds itself; path show says where it is and whether it is on PATH, and path remove takes it off. Uninstalling removes the entry. Nothing here needs Node, npm or a copy of the source: the executable carries its own runtime.

"%LOCALAPPDATA%\BitRaster\bitraster-cli.exe" path add

Output, errors and exit codes

Every command accepts --json, which puts exactly one JSON object on stdout and nothing else, so a script can parse it whole. Without it you get a short human line. Diagnostics always go to stderr. An error is an object with a code from the table below, a sentence, whether repeating the same request could succeed (retryable), and whether the work may have happened anyway (outcome). That last field is the one to read after a lost reply: an outcome of unknown means check the document before sending an edit again.

0
The command ran; its result is on stdout.
1
The command ran and failed: a missing file, a refused overwrite, a revision conflict, a busy document.
2
The request was wrong before it went anywhere: a bad option, a missing flag, an argument the contract refuses.
3
No editor to talk to: not running, Automation off, a version mismatch, or a stale connection record.
INVALID_REQUEST
Malformed requestnot retryable
UNKNOWN_COMMAND
No such commandnot retryable
UNSUPPORTED_VERSION
API version not servednot retryable
UNSUPPORTED_CAPABILITY
Command not available herenot retryable
REQUEST_TOO_LARGE
Request exceeds a limitnot retryable
INVALID_TARGET
Target did not resolvenot retryable
INVALID_PROJECT
Not a project this build can readnot retryable
OUTPUT_EXISTS
Output exists; overwrite not requestednot retryable
SNAPSHOT_MISMATCH
Input changed since it was inspectednot retryable
REVISION_CONFLICT
Document moved onnot retryable
REQUEST_ID_REUSED
Request id reused with other argumentsnot retryable
RESULT_UNKNOWN
Outcome no longer knownnot retryable, outcome unknown: reconcile before retrying
TIMEOUT
No reply in timenot retryable, outcome unknown: reconcile before retrying
CANCELLED
Cancelledretryable, outcome unknown: reconcile before retrying
BUSY
Document is busyretryable
UNSUPPORTED_STATE
Document state not automatednot retryable
APP_UNAVAILABLE
BitRaster is not reachableretryable
VERSION_MISMATCH
CLI and app versions differnot retryable
UNAUTHORIZED
Not this sessionnot retryable
DISCONNECTED
Connection lost mid-requestnot retryable, outcome unknown: reconcile before retrying
IO_ERROR
File operation failedretryable
INTERNAL
Internal failurenot retryable, outcome unknown: reconcile before retrying

Project files without the editor

inspect reads a project and prints its structure: canvas, color mode, layers with their ids, frames, tags, and a snapshot of the file's bytes. render writes one frame as a PNG through the editor's own compositor and lighting; export writes a spritesheet PNG and its Aseprite-format JSON together, or neither. Outputs are never overwritten unless you pass --overwrite, and are written whole or not at all. A build step in a shell:

bitraster-cli inspect hero.brpi --json > hero.inspect.json
bitraster-cli render hero.brpi --frame 0 --scale 4 --output preview.png --overwrite
bitraster-cli export hero.brpi --sheet out/hero.png --data out/hero.json --layout grid --padding 2 --trim --overwrite

Pass the snapshot from inspect back with --snapshot and a frame index is checked against the bytes it came from: if the file changed in between, the command refuses with SNAPSHOT_MISMATCH rather than rendering a different frame under the same number. Older project files mint fresh layer and frame ids every time they are read, which is why file commands address frames by index and snapshot.

Driving the open editor

Live access is on whenever the desktop app is running. Settings ▸ Automation shows whether the bridge is listening and is the switch that turns it off: the connection closes, its record is removed, and every handle a script was holding stops meaning anything, which is the one-click stop for a script or agent that has run away. Turning it back on starts a new session. Access is local to your user account on that computer; nothing about it leaves the machine. One thing to know: a BitRaster started with “Run as administrator” can be reached only from an administrator prompt, and both the CLI and Settings say so; relaunch it normally. Documents in your BitRaster Cloud account, in a shared room or being broadcast are listed but accept reads only.

bitraster-cli live documents --json

Each open document has a handle and a revision. The handle dies with the app session, so list again after a restart. Every edit names the revision it expects, and if the document moved on since, because you or another script drew, the edit is refused with REVISION_CONFLICT and nothing is applied: read the document again and decide with fresh eyes. A batch of actions is one undoable step, and a refusal in the middle of it leaves everything as it was.

# actions.json - a night sky and a crescent moon in five actions
[
  { "kind": "layer.create", "ref": "sky", "name": "Sky" },
  { "kind": "fill", "layer": { "created": "sky" }, "frame": { "index": 0 },
    "at": { "x": 0, "y": 0 }, "color": { "kind": "rgba", "r": 16, "g": 20, "b": 48 } },
  { "kind": "layer.create", "ref": "moon", "name": "Moon" },
  { "kind": "shape.ellipse", "layer": { "created": "moon" }, "frame": { "index": 0 },
    "from": { "x": 5, "y": 6 }, "to": { "x": 25, "y": 26 }, "filled": true,
    "color": { "kind": "rgba", "r": 250, "g": 236, "b": 170 } },
  { "kind": "shape.ellipse", "layer": { "created": "moon" }, "frame": { "index": 0 },
    "from": { "x": 11, "y": 4 }, "to": { "x": 29, "y": 22 }, "filled": true,
    "color": { "kind": "transparent" } }
]

bitraster-cli live create --width 32 --height 32 --name scratch --json
bitraster-cli live apply --document doc:...:doc7 --revision 0 --actions actions.json --json
bitraster-cli live render --document doc:...:doc7 --output check.png
bitraster-cli live undo --document doc:...:doc7 --revision 1 --transaction tx:1
bitraster-cli live save --document doc:...:doc7 --revision 2 --output scratch.brpi
bitraster-cli live close --document doc:...:doc7 --revision 2

apply returns the new revision and a transaction id. undo takes back that transaction only while it is still the latest thing that happened to the document; if you drew after it, the undo is refused rather than taking your stroke. Nothing is saved to disk until you say so: save writes the project at the revision you name, with its history and reference image, and marks it clean only if nothing changed while the file was being written. Rendering or exporting never marks a project saved. Points are document pixels from the top left; a stroke clips to the document's selection like a mouse stroke, and borrows nothing from the toolbar.

Actions

Every action is one of the editor's own tools or verbs, run the way a hand would run it. A paint color is RGBA in an RGBA document, a palette index in an indexed one, or transparent, which erases. mirror on a paint action runs the editor's symmetry about the canvas centre for that action alone. A layer is named by id, by index, or by the ref a layer.create or layer.group earlier in the same batch gave it; a frame by id or index.

layer.create
Add an empty layer, above a given layer or on top. ref names it for later actions.
layer.set
Rename, show or hide, lock, set opacity (0 to 1) or the blend mode of a layer or group.
layer.remove
Remove a layer, or a group with everything in it. Refused if no paintable layer would remain.
layer.move
Move a layer one step up or down among its siblings; up is towards the top of the stack.
layer.group
Wrap a layer (a group takes its contents along) in a new group. ref names the group.
layer.ungroup
Dissolve a group, leaving its rows where they are.
stroke.pencil
A pencil stroke through the given points, with a brush size; the same tool a mouse drives.
fill
The bucket at a point: contiguous by default, or every matching pixel on the cel; tolerance for RGBA.
shape.rect
A rectangle from one corner to the other, outline or filled, with a brush size.
shape.ellipse
An ellipse inside the box from one corner to the other, outline or filled.
region.move
Lift the pixels in a rect and put them down dx, dy away, leaving the source transparent.
region.copy
Copy the pixels in a rect to a new top-left, on the same or another layer and frame; transparent pixels do not overwrite.
frame.add
Add a frame after a given one or at the end, empty or duplicated from a frame, optionally with linked cels and a duration.
frame.remove
Remove a frame. Refused on the last one.
frame.move
Move a frame to another index.
frame.set
Set a frame's duration in milliseconds. Applied directly, not part of undo.
cel.link
Make the cels of one layer over a run of frames share one image, as the timeline links them.
cel.unlink
Give each cel in that run its own copy again.
tag.set
Add or replace (by name) a frame tag over a run of frames, with a direction and a color. Applied directly.
tag.remove
Remove a frame tag by name. Applied directly.
canvas.resize
Resize the canvas, keeping the art at the named edge or corner; trim drops what is left outside. Refused in a room.
palette.add
Append RGBA entries to the palette, up to 256 in all.
palette.set
Replace one palette entry; in an indexed document every pixel using it changes with it.

Three of these are applied directly rather than as recorded edits, exactly as the editor's own controls apply them: frame.set, tag.set and tag.remove. A rollback restores them, but the transaction's undo does not, and a watcher does not see them.

Commands

capabilities
What this host serves: API version, commands, formats, limits and error codes.no editor needed
version
The version of the answering component and of the API it speaks.no editor needed
ping
A correlated round trip to the running editor.needs the editor running with Automation on
inspect
Read a project file’s structure without opening the editor.reads a project file; no editor needed
render
Render one frame of a project file to PNG with the editor’s compositor.reads a project file; no editor needed
export.sheet
Export every frame as a spritesheet PNG plus Aseprite-compatible JSON.reads a project file; no editor needed
live.documents
The documents open in the editor, with handles and revisions.needs the editor running with Automation on
live.inspect
Structure of one open document.needs the editor running with Automation on
live.open
Open a project file in the editor, or return its handle if it already is.needs the editor running with Automation on
live.create
Create a new local document in the editor.needs the editor running with Automation on
live.apply
Apply a batch of edit actions as one undoable transaction.needs the editor running with Automation on; needs the expected revision
live.render
Render one frame of an open document, unsaved state included, at a named revision.needs the editor running with Automation on
live.undo
Undo the identified automation transaction, if it is still the latest.needs the editor running with Automation on; needs the expected revision
live.redo
Redo the identified automation transaction, if it is next.needs the editor running with Automation on; needs the expected revision
live.save
Save an open document at a named revision, in place or to a new path.needs the editor running with Automation on; needs the expected revision
live.close
Close an open document. Unsaved changes are refused unless `discard` is set.needs the editor running with Automation on; needs the expected revision
live.export.sheet
Spritesheet export of an open document at a named revision.needs the editor running with Automation on
live.pixels
Read pixels as data: one frame's composite, or one layer's own pixels, optionally within a rect. RGBA bytes, base64, row-major; an indexed layer also returns its indices.needs the editor running with Automation on
live.export.image
Export one frame as an image file (PNG, JPG, GIF or BMP) at a named revision.needs the editor running with Automation on
live.export.animation
Export the animation as a GIF at a named revision: every frame, or one tag, timed by frame durations or a fixed rate.needs the editor running with Automation on
live.import
Open an image (PNG, GIF, WebP, JPEG) or an Aseprite file as a new document; an animated GIF becomes frames.needs the editor running with Automation on
live.underlay.set
Put a reference image under the drawing to trace over (the tracing underlay). View state, not part of the document or its undo; the document is brought to the front.needs the editor running with Automation on
live.underlay.clear
Remove the tracing underlay. View state; the document is brought to the front.needs the editor running with Automation on

On the command line the file commands are inspect, render and export, and the live ones are live documents, live inspect, live open, live create, live apply, live render, live undo, live redo, live save, live close and live export. bitraster-cli help prints every flag.

For an AI agent: the MCP server

bitraster-cli mcp serves every command above as a tool over stdio, with input and output schemas the agent can read. File tools work with the editor closed; live tools need it running with Automation on. A render without an output path comes back as an image the agent can look at.

The installer registers it for you with every AI client it finds on the machine: Claude Desktop, Claude Code, Cursor, VS Code and Windsurf. Restart a client that was open during the install, then ask it to drive BitRaster; the tools are already there. For a client installed later, Settings ▸ Automation has a Register button, or run bitraster-cli mcp register; mcp status says who is registered, and uninstalling removes the entries. Only clients that are present are touched, a backup is kept beside each file that is rewritten, and a config that does not parse is left alone and reported. For any other client, point it at the executable by its full path:

{
  "mcpServers": {
    "bitraster": {
      "command": "%LOCALAPPDATA%\\BitRaster\\bitraster-cli.exe",
      "args": ["mcp"]
    }
  }
}

Replace %LOCALAPPDATA% with your actual folder if your client does not expand it, for example C:\\Users\\you\\AppData\\Local\\BitRaster\\bitraster-cli.exe. Tools take an optional requestId: an agent that mints one can repeat a call after a lost reply and get the outcome it already had instead of drawing twice. A tool call the editor has accepted is not undone by cancelling it; use live_undo.

Compatibility

The API version is 1.1 and is separate from the app version. Within a major version changes are additive: new commands, new optional fields. A request naming a higher minor than the host serves is refused rather than answered narrowly. The CLI and the app are installed together and refuse to work across versions (VERSION_MISMATCH); update both by updating the app. What this version does not do: headless JPG, BMP or GIF, index-map export, drawing tools other than the pencil, and editing documents that live in an account, a room or a broadcast. Each is a separate piece of work rather than a hidden option.

All reference pages