extension logs --follow and the act commands. You only need this page when you build your own harness against the socket. For everything else, the CLI verbs are the supported surface.
The dev server hosts the channel at path /extjs-control on the controlPort that ready.json publishes. Clients say hello with envelope version 1 and a role: producer, consumer, or controller.
The extension-develop package exports every type and constant on this page from its bridge-entry module, so a harness never has to copy wire strings into its own source.
LogEvent (version 1)
One log record per frame, withv: 1. The broker assigns seq on ingest and normalizes runId to the session’s ready.json value, so rows join the contract.
Optional locator fields ride beside them when known:
url, hostname, tabId, frameId, windowId, title, stack, errorName, sourceExtensionId, incognito, and a free-form data object.
A dx.signal event is a structured diagnostic that the runtime raises about the dev loop itself. Branch on its code and status, and surface remediation to the user.
ReadyFrame and capabilities
After a successful hello, the server answers with a ready frame:capabilities tells a controller what this session will accept: eval, storage, reload, the openable surfaces, and deepDom for deep DOM inspection. deepDom is a bridge capability field, not a CLI flag. bufferedFrom is the oldest buffered seq still replayable.
GapFrame
The broker drops records rather than stall, and it says so. A gap frame reports how many records you lost and why:reason is one of ring_overflow, rate_limit, disk_slow, or slow_consumer.
CommandFrame and results
Controllers issue commands with acmdId, an op, and a target context:
The answer is a result frame with the same
cmdId, ok, an optional value, and truncated plus durationMs when relevant. Command frames require a session started with --allow-control, and eval additionally requires --allow-eval.
Refusal codes
When the guest refuses a command, the result frame’serror.code carries a machine name beside the browser’s own sentence. Branch on the code, never on the prose:
The exported constants are
REFUSAL_NEEDS_HEADED_WINDOW, REFUSAL_NEEDS_USER_GESTURE, REFUSAL_SURFACE_NOT_OPEN, and REFUSAL_API_UNAVAILABLE.
WebSocket close codes
A close in the 4000 range is a deliberate refusal, never a transport failure:Other server frames
The server also broadcasts dev-loop frames that a harness should tolerate and may use:reload: a fire-and-forget reload signal to the service-worker producer, with areloadTypeoffull,service-worker,content-scripts, orpage. Thepagekind is notify-only.ping: a keepalive that resets the MV3 service worker’s idle timer. Ignore it.
Next steps
- Prefer the CLI verbs where they suffice, starting from ready.json.
- Map bridge failures onto envelope codes with Error codes.

