docs(browse): /health liveness vs active-tab responsiveness (#3247)

BROWSER.md's busy-vs-dead lifecycle note, ARCHITECTURE.md's daemon
model and the REMOTE_BROWSER_ACCESS /health reference now say that
`status` is daemon liveness, that `activeTab` reports the active tab
separately, and which commands keep working while a tab is busy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wb6Wntntmwau19fSuSbuaL
This commit is contained in:
Andrei VershininandClaude Opus 5.5 committed 2026-10-17 14:30:56 +00:00
1 parent ef70b7d880
commit 3dbb256796
3 files changed
+12 -2

No files matched your search

+1 -1
View File
@@ -91,7 +91,7 @@ The server writes `.gstack/browse.json` (atomic write via tmp + rename, mode 0o6
{ "pid": 12345, "port": 34567, "token": "uuid-v4", "startedAt": "...", "binaryVersion": "abc123" }
```
The CLI reads this file to find the server. If the file is missing or the daemon process is dead, the CLI spawns a new server. A process that is alive but not answering `/health` is busy, not dead: the CLI probes for a bounded ~8s, then reports busy with a nonzero exit — only an explicit `--force-restart` kills a live daemon. Process liveness uses signal-0 (`isProcessAlive`, EPERM counts as alive) on every platform, with the health check (GET /health) as the responsiveness signal. Daemon stdout/stderr persists to `<project>/.gstack/browse-daemon.log`.
The CLI reads this file to find the server. If the file is missing or the daemon process is dead, the CLI spawns a new server. A process that is alive but not answering `/health` is busy, not dead: the CLI probes for a bounded ~8s, then reports busy with a nonzero exit — only an explicit `--force-restart` kills a live daemon. Process liveness uses signal-0 (`isProcessAlive`, EPERM counts as alive) on every platform, with the health check (GET /health) as the responsiveness signal. Its `status` covers the daemon and its Chromium connection only; the active tab's main thread is reported separately (`activeTab.responsive`, a probe bounded to 1s), so one page stuck in a long script never makes the CLI refuse commands. Daemon stdout/stderr persists to `<project>/.gstack/browse-daemon.log`.
### Port selection
+8
View File
@@ -626,6 +626,14 @@ Storage stays intact by default. With explicit approval on a Chromium target, `-
| `tab-each <command> [args...]` | Fan out a command across every open tab; returns JSON |
| `frame <sel\|@ref\|--name n\|--url pattern\|main>` | Switch to iframe context (or back to main); clears refs |
**A busy tab is not a busy daemon.** `/health` `status` is daemon liveness
(Chromium connected); the active tab's main thread is reported separately as
`activeTab: { id, responsive }`, probed for at most 1s. While one page is stuck
in a long script, `status`, `tabs`, `tab <id>`, `newtab`, `closetab`,
`state save` and `stop` keep working, and `status` and `tabs` mark the tab as
not responding. A command that needs the stuck tab times out after 30s and
names it, so you can switch away or close it without `--force-restart`.
### Extraction
| Command | Description |
+3 -1
View File
@@ -81,7 +81,9 @@ Response: (plain text result of the command)
```
#### GET /health
Server status. No auth required. Returns status, tabs, mode, uptime.
Server status. No auth required. Returns status, activeTab, tabs, mode, uptime.
`status` is daemon liveness; `activeTab` (`{ id, responsive }`, or null with no
page) says whether the active tab's main thread answered within 1s.
Never carries a token — extension token bootstrap is `POST /extension-token`
(local listener only, validates the pinned `chrome-extension://` Origin and a
loopback Host; 403 otherwise). Not reachable over the tunnel (404).