The ngrok pair-agent tunnel could auto-start whenever ngrok was installed
and shipped active on every install, despite ~0.01% usage. Gate all three
activation points behind a single opt-in config flag so nothing is exposed
to the internet unless the user explicitly enables it.
- New `pair_agent` config key (off | on), default off, read via the shared
fail-closed `isPairAgentEnabled()` guard in browse/src/config.ts (honors
`GSTACK_PAIR_AGENT` env override for tests/emergency).
- CLI no longer auto-starts the tunnel when disabled, even if ngrok is
installed/authed; prints the enable command instead.
- `/tunnel/start` returns 403 with the enable hint when disabled (tunnel
listener never binds).
- `BROWSE_TUNNEL=1` startup path skips the tunnel bind when disabled.
Local browse/QA (local listener, /command, /browse, /qa, cookie import,
/inspector, /health) is unchanged. When enabled, behavior is identical to
before.
The /pair-agent skill doc is parity-locked GStack 2 legacy (evals/parity/
contracts/pair-agent.json pins the render + blob SHAs). Its up-front
"enable pair_agent first" wording needs a separate parity-aware regen and
is intentionally not touched here.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>