Relationships
#3963 A long-lived serve client for extensions, and a stable rate_limited error code
Opened by skunk-ape · 10/26/2026
Problem
Extensions that read a remote serve on the operator's behalf (the stagecraft remote studio, swamp-club #3906, #3918) can only do it by running swamp <command> --server <url> --json once per read. Each run boots the full CLI (about 300 MB, 40-80% CPU on a Mac) and opens its own WebSocket, so a studio page counts against serve's per-IP burst limit of 50 connections per 60 s (#3399) once per read. Behind a shared NAT it locks out every other client on that address.
The serve WebSocket protocol already carries many id-tagged requests on one connection (data.query, model.search, model.get, ...). But the operator's identity (stored login and refresh, SWAMP_SERVER_TOKEN, --ca-cert, SWAMP_SERVE_EXTRA_HEADERS) is only handled inside the CLI. An extension cannot hold that connection itself without copying all of it against a private, unversioned protocol.
Ask
- A long-lived client process. For example
swamp client --server <url> --json: it reads one JSON request per line on stdin (a read command and its arguments, with a caller-chosen id), answers one JSON line per request on stdout, and keeps one authenticated WebSocket to serve, reconnecting with backoff. Every read keeps carrying the operator's login and grants, as--serverdoes today. Read commands are enough to start with:model search,model get,data query. - A stable rate-limit signal. Today a 429 handshake becomes the message "Rate-limited by server — try again later" (src/cli/remote_run.ts), with no
codein the --json error and exit 1. Give it"code": "rate_limited", exit 75 (EX_TEMPFAIL, as the help already describes for temporary failures) and the retry-after when serve sends one. The long-lived client would report the same code per request.
Why
The stagecraft studio is landing a stagecraft-only mitigation in #3906: a fixed number of reads per page load and per poll, and backing off on rate limiting by matching the message text. The single connection #3918 asked for waits on (1). Matching the message is a stopgap until (2).
Related: #3399 (the configurable burst limit and per-credential buckets), #3906, #3918.
Open
No activity in this phase yet.
Sign in to post a ripple.