Desktop Material

Local Agent HTTP API

Desktop Material ships an opt-in Agent API for trusted automation. The main process owns one versioned command contract and publishes it through a REST compatibility surface and sessionless MCP JSON-RPC. The renderer executes each accepted command through the same stores and safety checks as the visible UI.

Behavior and configuration

Open Settings → Agent access, choose Local only (recommended), and turn on Enable agent server. Desktop Material listens on 127.0.0.1 at a random port and shows the effective base URL and desktop bearer token. The server is off by default. Regenerating the token invalidates the previous desktop token; stopping the server removes its runtime connection file.

The separately enabled Paired LAN devices mode binds a private IPv4 interface, exchanges a five-minute one-use pairing code for a per-device token, and can use an explicitly configured HTTPS gateway. Direct LAN HTTP authenticates but does not encrypt traffic. YOLO LAN requires explicit confirmation, disables authentication, rejects HTTPS gateways, and returns to local/off when the app restarts. It should be treated as unsafe.

Open the mobile connection page

The Mobile connection card remains discoverable in Settings → Agent access in every mode. Choose Paired LAN devices and start the server, then select Open mobile connection page. Desktop Material replaces any existing pairing code, builds a fresh five-minute one-use /connect URL from the saved remote-site address, and opens it in the default browser. The button is disabled until paired mode is running, so Local-only and stopped-server states cannot accidentally create a LAN pairing.

The one-time secret is carried only in the URL fragment. Browsers do not send that fragment to the site server, and the mobile client removes it from browser history before exchanging it for a vault-backed device token. Opening the button again invalidates the prior code. If browser launch or pairing-code creation fails, Settings reports a generic localized error without displaying or logging the secret; create another connection after checking the remote-site address and server state.

HTTP routes

Every POST route requires Content-Type: application/json. The current REST route accepts only name and args; command arguments must be JSON objects. REST command success returns { "ok": true, "data": ... }; a command-level failure returns HTTP 422 with { "ok": false, "error": ... }. Transport and validation failures use an HTTP status plus an http_<status> error code.

Version 1 command catalog

Repository commands that require an exact target accept either repositoryId or path. clone-batch accepts 1–50 items. A saved-host SSH clone accepts a 32-character lowercase hexadecimal host ID, a credential-free Git URL, and an absolute or home-relative POSIX destination. run-automation accepts commit-and-push, merge-branches, or merge-worktrees.

The active profile can add validated read functions as github_api_<function-name>. They appear in both /api/v1/info and MCP tools/list. REST callers can post function arguments directly to the dynamic command name or use invoke-api-function. Write and destructive definitions remain discoverable but cannot bypass the app's interactive mutation review.

Postman workflow

Import either the category collection or the master collection. Create a private, unexported Postman environment with these values:

The committed defaults use an unreachable port, .invalid URLs, empty secret fields, and replace-me paths. Read request descriptions before sending a mutation. Do not save a real token or pairing code into either collection, a shared environment, an export, logs, screenshots, or source control. In Local mode, omit the Origin header; browser-origin requests are rejected.

Persistence and configuration boundaries

The access mode, remote-site setting, optional gateway, and preferred LAN port are local application settings. The running app writes a restricted agent-server.json discovery file for the shipped CLI and stdio proxy. It contains live connection material and must not be copied into a repository or opened merely to populate Postman. Paired-device display metadata is stored separately from tokens; tokens live in the operating-system credential vault. Repository credentials and provider tokens never appear in Agent API results.

Failure modes and recovery

Security considerations

Local mode accepts only loopback clients and validates the exact Host header. All modes cap request bodies, bound concurrency, reject credential-shaped keys and pathological nesting before renderer execution, redact credential-shaped output, and send no-store plus defensive response headers. The bearer token protects Local and Paired LAN modes; paired tokens are independently revocable. Pairing secrets are rate-limited, expire after five minutes, and are consumed before vault storage so they cannot be replayed after a partial failure. The Settings browser action always generates a new secret and passes the complete fragment URL directly to the operating-system browser opener; it does not put the URL into logs, source control, site requests, or persistent application settings.

Mutating commands change repositories or provider state. Use exact repository selectors, inspect status first, and keep the Postman examples pointed at disposable fixtures until their effects are understood. Never expose a Paired LAN port outside a trusted private network without the configured HTTPS gateway, and do not use YOLO LAN on a network containing untrusted clients.

Verification

The implementation contract lives in app/src/lib/agent-commands.ts and the HTTP/MCP routing in app/src/main-process/agent-server/. Unit coverage verifies the current and legacy REST forms, MCP discovery and calls, dynamic named functions, token rejection and rotation, Host/Origin policy, body limits, pairing expiry and one-use exchange, device revocation, LAN mode boundaries, gateway policy, fresh browser-link generation, unavailable-mode and browser-failure handling, queue bounds, shutdown, redaction, the CLI, and the stdio proxy. The checked-in Postman files are parsed as JSON and audited against all eight shipped route patterns and all 24 static command names.