Files
wordcraft/docs/control-protocol.md
T
780fd7a5af Control server closes on non-JSON input; hyperlinks follow only http/https/mailto (#34) (#72)
The control server answered a line that wasn't JSON with an error and kept
reading, so an HTTP request to the port (for example a web page's fetch to
127.0.0.1) could carry a command such as file.saveAs in its body. It now
replies once and closes the connection on the first bad line; HTTP request
lines never parse, so nothing after them runs.

Ctrl/Cmd+click on a hyperlink passed any URL to the system. It now follows
only http, https and mailto links, and shows a status message otherwise, so
a document can't launch file: paths or custom-scheme handlers.

Tests cover JSON requests, closing on bad JSON, an HTTP POST carrying a
command, and the link allow-list. The control protocol docs note the
closing behaviour.

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 06:16:28 -04:00

2.1 KiB

Control protocol

Start the app with a control port: wordcraft --control 7981 (or WORDCRAFT_CONTROL_PORT=7981). It listens on 127.0.0.1 only. Send one JSON object per line; each gets one reply line:

{"id": 1, "method": "engine.execute", "params": {"command": "text.insert", "params": {"text": "Hello"}}}
{"id": 1, "ok": true, "result": {"anchor": {...}, "focus": {...}}}

Errors come back as {"id": …, "ok": false, "error": "message"}. A failed command leaves the document unchanged. A line that isn't valid JSON gets one error reply, then the server closes the connection (so an HTTP request sent to the port can't run a command); reconnect to continue.

Methods

Method Params Result
engine.execute command, params the command's result (any id from engine.commands, including UI commands ui.tab, ui.dialog, ui.backstage, ui.language (`{"value": "auto"
engine.commands — every command: id, label, location, shortcut, params, enabled
document.inspect text? blocks (text, style, runs, lists, tables), parts, sections, selection, pages
ui.inspect — UI state, view, dialog, window size, page rects on screen, caret, perf
ui.click x, y, button?, count?, shift?, cmd?, alt? real pointer input at window coordinates
ui.clickText page (0-based), x, y (points from the page's top-left), count? click inside a page
ui.move / ui.drag x,y / x,y,toX,toY,steps? pointer move / drag
ui.key key (B, Enter, Left…), shift?, alt?, cmd? key press through egui (shortcuts apply)
ui.text text typed text through egui
ui.screenshot path? PNG of the window
ui.render path, page? (1-based), scale? PNG of a page, rendered by the engine
ui.parity — feature-catalog parity
ui.resize / ui.focus / app.quit window control

Any other method name is treated as a command id: {"method": "format.bold"} works.

Positions are {"story": "body" | {"part": n}, "path": [block, row, cell, block, …], "off": byteOffset}.