Proposal: opt-in local HTTP API so AI agents and tools can drive Responsively
Motivation
AI coding agents (Cursor, Claude Code, Codex and friends) are now a common way people build web UIs — but they're blind to responsive behaviour. An agent can edit CSS, yet has no way to see the result across breakpoints. Responsively is uniquely positioned here: it already renders a page on many devices simultaneously. If agents could drive it, "check this looks right on mobile" becomes a single tool call in the loop, and Responsively becomes part of the agentic workflow rather than a manual step after it.
The same surface also unlocks CLI/CI use cases the community has asked about, such as capturing screenshots of every device profile in a script.
Proposal
Add a small, opt-in, localhost-only HTTP API embedded in the app's main process. Disabled by default; enabled via a checkbox in Settings. On top of this contract, follow-up (separately published) packages can provide an MCP server for AI agents and a thin CLI — neither affects the app itself.
v1 surface (deliberately minimal):
GET /— handshake (app + API version)GET /api/v1/state— current URL, zoom, active suite and devicesPOST /api/v1/navigate— load a URL (same flow as the address bar), wait for webviews to settleGET /api/v1/devices— device catalogue incl. custom devicesGET /api/v1/suites/PUT /api/v1/suites/active— list and switch preview suitesPOST /api/v1/screenshot— capture one/all devices, optional full-page, path or base64 response
Every device-scoped response uses a uniform { device, result | error } envelope, with per-device failures isolated.
Security model
- Binds
127.0.0.1only, on an ephemeral port. - Bearer token (32 random bytes, timing-safe comparison) generated per session; port + token written to a discovery file (
~/.responsively/api.json, mode 0600, removed on quit) that local clients read. - No CORS headers ever emitted, so web content cannot read responses.
- Off by default; nothing listens unless the user opts in.
Implementation notes
- Zero new runtime dependencies —
node:httpplus a tiny router; six routes don't justify a framework. - A single main↔renderer "command bridge" (request/response IPC with correlation IDs) lets the server execute renderer-owned actions (address, active suite, webview access). This is the reusable seam for any future capability.
- Screenshots reuse the existing pipeline (
src/main/screenshot/), with the capture orchestration in the deviceToolbarextracted to a shared util so UI and API stay on one code path; API captures skipshell.showItemInFolder. - Tests: Vitest for router/auth/discovery/bridge; a Playwright spec in the existing e2e harness exercising all routes.
Explicitly out of scope for v1: interaction scripting (click/type — Playwright's job), arbitrary JS evaluation, console log capture, colour-scheme emulation, suite/device CRUD, headless mode. Several of these are natural v2 candidates once the seam exists.
Delivery plan
I'm happy to implement this as two reviewable PRs:
- Command bridge + server + all routes except screenshot + settings toggle + unit tests + docs.
/screenshot(includes the small screenshot refactor) + e2e spec.
Questions for maintainers
- Are you open to this direction in principle?
- Naming/copy: "Local API" vs "Automation API" for the settings toggle?
- Discovery file location:
~/.responsively/api.json(proposed, so clients need no per-OS logic) vs Electron'suserDatadir? - Any preference on live start/stop when toggling the setting vs requiring an app restart (live is planned, restart-only is simpler)?
Source: responsively-org/responsively-app