Architecture
reins is three small pieces with one narrow contract between them. Everything runs on your machine, and everything binds 127.0.0.1.
your agent Claude Code, Cursor, Codex, anything with a shell
│ shells out
▼
reins CLI @karnstack/reins
│ HTTP /rpc · 127.0.0.1 · daemon auto-spawned
▼
reins daemon one per machine, serves every browser
│ WebSocket · allowlisted chrome-extension:// origins
▼
reins extension MV3; an offscreen document holds the socket
│ chrome.debugger · Chrome DevTools Protocol
▼
your tabs Chrome, Brave, Edge, Arc, DiaThe CLI
The whole interface. Agents already have a shell, so there is no MCP server to register. A skill (npx skills add karnstack/reins) teaches them the commands.
The daemon
Started by any CLI command. It takes HTTP /rpc calls from the CLI and holds the WebSocket each browser's extension connects to. Logs are in ~/.reins/logs/.
The extension
Its service worker runs commands through chrome.debugger. An offscreen document holds the WebSocket, because Chrome suspends idle MV3 service workers.
It finds the daemon by trying a few localhost ports, and proves who it is by its chrome-extension://<id> origin, which pages cannot fake.
Multiple browsers
Each browser with the extension connects to the same daemon. With more than one connected, pass --browser <id>. reins never guesses; it errors and lists the ones it sees.
Element refs
reins snapshot gives each control a ref (e5: button "Submit"). Refs survive repaints better than hand-written selectors. --selector takes CSS when you need it.