Web UI & remote access
The same frontend the desktop app renders, served over HTTP — as an embedded toggle in the desktop app, or as the standalone specforge-serve binary on a machine with no display. Off by default, loopback by default, and deliberate about every step beyond that.
The embedded server
Settings ▸ Web UI in the desktop app serves SpecForge at http://127.0.0.1:<port> — a browser tab mirroring the app’s live state, useful for a second monitor or a browser-native reading setup. It binds loopback only, and no setting exists that can move it onto a network interface.
specforge-serve
The standalone binary serves the same UI without the desktop app — a homelab box, a headless server, the machine where the repositories actually live. It binds 127.0.0.1:4317 by default and renders the workspaces registered on the machine running it.
The web UI behaves like a site, not a port of an app: browser back and forward work, and every view has a durable URL you can bookmark or paste. Settings that only make sense on the desktop are hidden.
If 4317 is already taken, --port moves it. Both it and --bind also read from the environment, which is the easier route under a service manager — a flag beats the environment, and the environment beats the default:
specforge-serve --port 8080
SPECFORGE_WEB_PORT=8080 specforge-servespecforge-serve --help prints the whole surface, which is deliberately small: --bind, --port, --help and --version.
Getting specforge-serve
The server publishes to npm as @avantmedia/specforge, so the shortest route to a running instance is one command inside any workspace:
cd ~/some-openspec-workspace
npx @avantmedia/specforgenpx re-resolves the package on every invocation. For a server you intend to leave running, install it once instead:
npm install -g @avantmedia/specforge
specforge-servemacOS on Apple Silicon and Intel, Linux on x64 and arm64, and Windows on x64 are all covered, and npm fetches only the binary matching the machine. There is no install script and nothing is pulled from outside the registry, so the package installs under --ignore-scripts, from an offline cache, and through a private mirror.
xattr step the standalone archives need does not apply to an npm install.Every release also ships specforge-serve as a standalone archive — macOS universal, Linux x64 and arm64, Windows x64 — if you would rather not involve npm. The Linux builds are statically linked, so one binary covers Alpine and containers as well as glibc distributions.
The trust boundary
Reachability and authorisation are separate concerns. The bound interface decides who can open a socket; a request-authority allow-list decides which page may drive the API. On loopback, every request’s Origin and Host are checked against known authorities — loopback itself, plus your machine’s own Tailscale name when that is enabled — so a stray web page in your browser cannot quietly drive a server that reads your filesystem.
Review actions and the browser
The browser skin reads GitHub and BitBucket data — pull requests, changed files, conversations and checks — but it never posts a review. Only the native desktop app can submit a comment, reply, approval or request for changes, and only after an explicit native confirmation. The terminal does not post reviews either.
Serving the browser UI grants no provider-write authority: opening or publishing it cannot turn a provider read into a review write, and GitHub and BitBucket access stays off until a credential is configured in the desktop app. SpecForge never merges a pull request, from any surface.
Remote access, the sanctioned way
For access beyond the machine, SpecForge supports Tailscale Serve: the proxy connects to the loopback port, and SpecForge trusts your machine’s own tailnet name — resolved automatically, with a manual override, and failing closed when no name is available. The server itself never binds a network interface for this.
An optional allow-list of Tailscale logins narrows it further: when set, a proxied request is accepted only if Tailscale identifies the visitor as one of those users. Left empty, the tailnet itself is the boundary. Local loopback requests never need a login, and Tailscale Funnel — public-internet exposure — is not supported at all.
An SSH tunnel (ssh -L 4317:127.0.0.1:4317 host) works too, with no configuration: from the server’s point of view you are a loopback visitor.
The --bind escape hatch
specforge-serve --bind 0.0.0.0 publishes the UI on a network interface directly — unauthenticated, with the authority checks necessarily stood down. The network you publish on, and every site any browser on it visits, becomes the trust boundary. It exists for networks you genuinely trust; the flag is per-invocation and never persisted, so the exposure cannot outlive the command that asked for it.
specforge-serve refuses to start rather than run with the gate silently disabled.On a tablet or phone
Once it is reachable from your tailnet, the web UI is a reasonable way to read specs away from the desk. The served document declares its own icon set, so adding it to a home screen gives you a SpecForge mark and a full-screen window rather than a browser chrome and a generic glyph.
The interface answers touch and pen directly: pane dividers are dragged through pointer events, and the controls that have no hover equivalent — the collapse chevrons, the favourite star — stay visible at rest instead of appearing on hover, with larger hit areas on coarse pointers. None of that changes anything on a desktop with a mouse.