Proposal: opt-in local HTTP API so AI agents and tools can drive Responsively

Author: davidmansarayCreated Aug 28, 2026Updated Aug 28, 2026

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 devices
  • POST /api/v1/navigate — load a URL (same flow as the address bar), wait for webviews to settle
  • GET /api/v1/devices — device catalogue incl. custom devices
  • GET /api/v1/suites / PUT /api/v1/suites/active — list and switch preview suites
  • POST /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.1 only, 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 dependenciesnode:http plus 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 device Toolbar extracted to a shared util so UI and API stay on one code path; API captures skip shell.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:

  1. Command bridge + server + all routes except screenshot + settings toggle + unit tests + docs.
  2. /screenshot (includes the small screenshot refactor) + e2e spec.

Questions for maintainers

  1. Are you open to this direction in principle?
  2. Naming/copy: "Local API" vs "Automation API" for the settings toggle?
  3. Discovery file location: ~/.responsively/api.json (proposed, so clients need no per-OS logic) vs Electron's userData dir?
  4. 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