Developers
Headless runs
Run Arx without windows from scripts, agents and CI, with a local MCP endpoint and only the grants you pass.
This page is a first draft. It may change before the public beta.
Arx --headless starts the browser without windows, a Dock icon or a menu bar. It runs the same browser and the same local MCP server as the app, and gives its own MCP client only the grants you pass. Every run ends with a clean stopped event.
Start a run
/Applications/Arx.app/Contents/MacOS/Arx --headless --allow read,screenshots,content --viewport 1280x800
| Option | Meaning |
|---|---|
--allow | Comma-separated grants for the run's MCP client: read (required), screenshots, content, interaction, manage. Default read. The client sees every space of the run's profile. manage approves changes in advance for the whole run, or until --timeout. |
--profile <absolute path> | Use and keep a persistent profile. By default each run gets a fresh private profile that is deleted at exit. |
--viewport <W>x<H> | Page size in points, 320×240 to 3840×2160. Default 1280×800. |
--timeout <seconds> | Optional deadline, 10 to 86,400. The run exits with 75 when it's reached. Default: none. |
--mcp-configuration <absolute path> | Where to write the MCP client configuration. The file must not exist yet; it's created readable only by you. Default: mcp.json in the run's directory. |
--url <url> | First page for a new profile: http(s) or about:blank (default). |
Start your MCP client with the mcpServers.arx entry of that configuration file. It launches Arx's bundled helper with the run's one-time credential.
Events
Stdout carries only events, one JSON object per line:
| Event | Fields |
|---|---|
ready | configuration, profile, viewport, grants, grantsExpireAt, timeoutSeconds, pid |
stopping | reason: signal, timeout, failure, parentExited, launcherExited or inputClosed |
error | code, message, exitCode |
diagnostic | code, for example shutdownSlow (with seconds) or authenticationProtected |
rendererFailed | tabID of a page whose renderer died. A reload recovers it. |
authenticationRequired | tabID of a page that hit an HTTP authentication challenge |
userActionRequired | tabID and prompts (webAuthentication, federatedSignIn) |
stopped | exitCode, suppressedDialogs |
{"event":"ready","grants":["read","screenshots","content"],"viewport":"1280x800", …}
{"event":"stopping","reason":"signal"}
{"event":"stopped","exitCode":0,"suppressedDialogs":0}
Wait for ready before connecting. Diagnostics from Arx and Chromium go to stderr.
Stopping
Send SIGTERM or SIGINT. A run without --timeout also stops when:
- the process that started it exits;
- an outer launcher in a chain such as
npx→node→ Arx exits; - stdin was a pipe at startup and reaches end of file. Keep the pipe open for as long as the run should last.
Exit codes
| Code | Meaning |
|---|---|
0 | Stopped on request |
64 | Invalid options |
69 | Engine or MCP endpoint unavailable |
70 | Startup failure |
73 | Profile in use or can't be created |
75 | --timeout reached |
2 | Shutdown hung and was forced to exit |
Nobody is watching
A headless run never waits for a person:
- A change outside the run's grant fails with
userActionRequired. - Page
alert,confirmandpromptdialogs get Chromium's default answer, and permission requests are denied. - HTTP authentication, passkey and federated sign-in prompts are cancelled and reported as events. Sign-in handoffs aren't available.
- Arx writes no screenshot files.
browser_capturereturns the image to the client.
A persistent profile is locked for the run: a second run on it, or Arx already open on it, is rejected with profileInUse.