Paintless
Latest
/Pipeline

CLI Reference

The paintless command — the local dev host that the widget and extension connect to.

The paintless CLI runs the local dev host: a WebSocket server the widget or extension connects to, which applies agent edits to your working tree and reports progress back to the browser. It is dev-mode only — production uses the server.

npx paintless dev

paintless dev

Starts the dev host. Without a config file it runs the Claude Code agent against your project; with a paintless.config.* it uses whatever agents and destinations you declare (see Configuration).

paintless dev [--port <port>] [--host <addr>] [--root <dir>] [--config <file>] [--allow-origin <url>]
FlagDefaultPurpose
--port <port>7327WebSocket port the widget connects to. Must match the widget's host if you change it.
--host <addr>127.0.0.1Interface to bind. The socket is unauthenticated, so binding anything else exposes your repo to that network — the host warns when you do.
--root <dir>current directoryProject root the agent edits and commits in. Everything the agent can touch lives under this path.
--config <file>auto-detectedPath to a paintless.config.{ts,js,mjs}. TypeScript is loaded through jiti, so no build step.
--allow-origin <url>Extra browser origin allowed to connect. Repeatable. See below.
--help, -hPrint usage.

The default port 7327 is also the widget's default host — change one and you must change the other.

--root is the agent's boundary

Whatever you pass as --root is the entire surface the agent can read and edit, and where commits land. Point it at the project you are working on. Pointing it at a monorepo root means the agent may touch any package in it.

Windows 8.3 short paths (KYECHA~1) break the embedded agent's path checks, so the CLI expands the root through realpathSync.native. Pass long-form paths when you script it.

Origin allow-list (--allow-origin)

The dev host only accepts WebSocket connections from localhost / loopback origins. This blocks cross-site WebSocket hijacking — a malicious page you visit while paintless dev is running must not be able to push code changes into your tree. Non-browser clients (tests, tooling) send no Origin header and are allowed.

To connect from another origin — a dev server on a LAN address, say — add it explicitly, repeating the flag per origin:

paintless dev --allow-origin http://192.168.1.20:5173 --allow-origin https://staging.local

See Security for the full posture.

What a session looks like

  1. The widget connects and handshakes (hello).
  2. You pick an element and submit — the host receives a ChangeRequest, status goes running.
  3. The agent edits the working tree in place; HMR shows it. Status goes pending — the change is applied but uncommitted.
  4. You Commit (a clean git commit) or Discard (revert) from the browser.

Only one change may await review at a time, and changes across all connected tabs are serialized, so two agents never edit the same tree at once.

Programmatic use

The package also exports startDevServer for embedding the host in your own tooling:

import { startDevServer } from 'paintless'
import { loadConfig } from 'paintless'

const config = await loadConfig(root)
startDevServer({ root, config, port: 7327, allowedOrigins: [] })
Edit this page

Last updated: