gstack /open-gstack-browser:启动 GStack Browser,让 AI 的浏览器操作全程可见可控
open-gstack-browser 是 gstack 技能包中的一个"有头浏览器"入口技能:它通过编译产物 browse CLI 以 headed 模式启动重品牌化的 GStack Browser(Playwright 托管的 Chromium),自动加载侧边栏扩展、应用反自动化隐身补丁,让你能实时观察并交互 Claude 的每一次浏览器操作。读完本篇,你将掌握该技能的完整调用流程(SETUP 检查、前置清理、连接、校验、Side Panel 引导、演示与侧边栏聊天),并能对照 browse CLI 源码、浏览器管理器 与 扩展清单 理解其端口约定、状态文件与守护进程保护机制。
1. 技能定义:frontmatter 与触发方式
技能定义文件为 open-gstack-browser/SKILL.md(由 SKILL.md.tmpl 经 bun run gen:skill-docs 自动生成,文件头注释明确标注 "AUTO-GENERATED from SKILL.md.tmpl — do not edit directly")。其 frontmatter 声明如下:
| 字段 | 取值 | 说明 |
|---|---|---|
name |
open-gstack-browser |
技能名,即 /open-gstack-browser |
preamble-tier |
1 |
使用第 1 档共享 preamble |
version |
0.2.0 |
技能版本 |
description |
Launch GStack Browser — AI-controlled Chromium with the sidebar extension baked in | 触发路由依据 |
triggers |
open gstack browser、launch chromium、show me the browser |
文本触发词 |
allowed-tools |
Bash、Read、AskUserQuestion |
技能运行期允许的工具 |
从 SKILL.md.tmpl 的 frontmatter 还能看到 voice-triggers: "show me the browser"(语音输入别名)。文档 "When to invoke" 一节列出的口语化触发语包括:"open gstack browser"、"launch browser"、"connect chrome"、"open chrome"、"real browser"、"launch chrome"、"side panel"、"control my browser"。技能声明的效果是:打开一个可见浏览器窗口,侧边栏提供实时活动流(activity feed)与聊天,内置反机器人隐身。
2. Preamble:每次技能运行前必须先执行的环境探测
SKILL.md 中 "Preamble (run first)" 是一段必须最先执行的 bash 脚本(所有 gstack 技能共享该段落,由模板中的 {{PREAMBLE}} 占位符注入)。它完成的环境探测对本技能运行至关重要,关键输出变量包括:
BRANCH:当前 git 分支(git branch --show-current);PROACTIVE/PROACTIVE_PROMPTED:是否允许主动建议技能;SKILL_PREFIX:为true时技能以/gstack-*名称呈现,磁盘路径仍是~/.claude/skills/gstack/[skill-name]/SKILL.md;REPO_MODE(经gstack-repo-mode探测)与SESSION_KIND(spawned/headless/interactive,非法值回落interactive);CONDUCTOR_SESSION:当运行在 Conductor 宿主(CONDUCTOR_WORKSPACE_PATH或CONDUCTOR_PORT非空)且非 headless 时输出true——此时 AskUserQuestion 不可靠,技能改用纯文本呈现决策;MODEL_OVERLAY: claude、GSTACK_PLAN_MODE(active/inactive,依据CLAUDE_PLAN_FILE、GSTACK_PLAN_MODE等变量判定)、UPDATE_CHECK、TELEMETRY、EXPLAIN_LEVEL、CHECKPOINT_MODE/CHECKPOINT_PUSH等。
Preamble 还会:写会话心跳文件 ~/.gstack/sessions/$PPID 并清理 120 分钟以上的过期会话;在 telemetry != off 时向 ~/.gstack/analytics/skill-usage.jsonl 追加一条 skill-usage 记录;经 gstack-slug 解析项目标识后加载该项目的 learnings.jsonl(超过 5 条时自动 gstack-learnings-search --limit 3);并执行 "Artifacts Sync" 段——读取 ~/.gstack-artifacts-remote.txt(或旧的 ~/.gstack-brain-remote.txt)、按 24 小时节流执行 gstack-brain-sync --once、在 gbrain 已配置时打印 worktree 级 pin 状态(<repo>/.gbrain-source)。
与之配套的通用行为协议在 Preamble 之后成文,值得了解:
- Plan Mode 安全操作:plan mode 下
$B、$D、codex exec/codex review、写~/.gstack/、写 plan 文件以及用open打开生成物均被允许; - 技能在 plan mode 中优先:技能文件被视为可执行指令,从 Step 0 逐步执行;
PLAN MODE EXCEPTION — ALWAYS RUN标记的命令(如遥测)照常执行; - 完成状态协议:技能结束必须报告
DONE/DONE_WITH_CONCERNS/BLOCKED/NEEDS_CONTEXT之一; - 自我改进:结束前必须回顾会话并记录持久性学习(
gstack-learnings-log),确无收获时显式输出 "No durable learnings this session"; - 遥测(最后运行):将
gstack-timeline-log完成事件写入本地时间线,并按telemetry开关决定是否追加本地 JSONL 与远端遥测。
3. SETUP:先确认 browse 二进制已构建
在任何 browse 命令之前,技能要求执行 SETUP 探测,确定 $B(browse CLI 路径):
_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
B=""
[ -n "$_ROOT" ] && [ -x "$_ROOT/.claude/skills/gstack/browse/dist/browse" ] && B="$_ROOT/.claude/skills/gstack/browse/dist/browse"
[ -z "$B" ] && B="$HOME/.claude/skills/gstack/browse/dist/browse"
if [ -x "$B" ]; then
echo "READY: $B"
else
echo "NEEDS_SETUP"
fi
解析顺序是:仓库本地 vendored 安装(<repo>/.claude/skills/gstack/browse/dist/browse)优先,其次全局安装($HOME/.claude/skills/gstack/browse/dist/browse)。若输出 NEEDS_SETUP:
- 先询问用户 "gstack browse needs a one-time build (~10 seconds). OK to proceed?" 并停下等待确认;
- 确认后运行
cd <SKILL_DIR> && ./setup; - 若
bun未安装,按文档给出的脚本安装(固定BUN_VERSION="1.3.10",对安装脚本校验 SHA-256bab8acfb046aac8c72407bdcce903957665d655d7acaa3e11c7c4616beae68dd,校验失败则拒绝执行)。
这对应 BROWSER.md Quick start 中的构建方式:bun install && bun run build 产出 browse/dist/browse(约 58MB 的编译 CLI),随后 B=./browse/dist/browse 一次设置、长期复用。browse CLI 是一个薄客户端:读取状态文件、向本地 Chromium 守护进程发 HTTP 请求、把纯文本响应打印到 stdout,单次往返约 100–200ms,不产生上下文 token 开销。
4. Step 0:连接前的清理(Pre-flight cleanup)
连接前先杀掉残留的 browse 服务并清理崩溃后可能滞留的 Chromium 配置文件锁,避免 "already connected" 的假阳性与 profile 锁冲突:
# Kill any existing browse server
if [ -f "$(git rev-parse --show-toplevel 2>/dev/null)/.gstack/browse.json" ]; then
_OLD_PID=$(cat "$(git rev-parse --show-toplevel)/.gstack/browse.json" 2>/dev/null | grep -o '"pid":[0-9]*' | grep -o '[0-9]*')
[ -n "$_OLD_PID" ] && kill "$_OLD_PID" 2>/dev/null || true
sleep 1
[ -n "$_OLD_PID" ] && kill -9 "$_OLD_PID" 2>/dev/null || true
rm -f "$(git rev-parse --show-toplevel)/.gstack/browse.json"
fi
# Clean Chromium profile locks (can persist after crashes)
_PROFILE_DIR="$HOME/.gstack/chromium-profile"
for _LF in SingletonLock SingletonSocket SingletonCookie; do
rm -f "$_PROFILE_DIR/$_LF" 2>/dev/null || true
done
echo "Pre-flight cleanup done"
从源码结构看,这段清理与 CLI 内部机制是呼应的:browse/src/cli.ts 中定义了 chromiumProfileDir()(返回 ~/.gstack/chromium-profile)与 cleanChromiumProfileLocks()(删除 SingletonLock/SingletonSocket/SingletonCookie 三个锁文件,注释标注对应 issue #1781——曾出现上次 Chromium 的 SingletonLock 阻塞自动重启导致"自伤性 crash-loop"),并有 killOrphanChromium() 在启动前清理仍持有锁的孤儿进程。
5. Step 1:$B connect 启动 GStack Browser
$B connect
按技能文档,connect 会以 headed 模式启动 GStack Browser(重品牌化的 Chromium),具备:
- 一个可见窗口——不是你的日常 Chrome,日常 Chrome 完全不受影响;
- gstack 侧边栏扩展经 Playwright 的
launchPersistentContext自动加载; - 反自动化隐身补丁(文档称 Google、NYTimes 这类站点无需验证码即可加载;见下文边界说明);
- 自定义 user agent 与 Dock/菜单栏中的 "GStack Browser" 品牌;
- 一个侧边栏 agent 进程,用于执行聊天命令。
connect 会自动从 gstack 安装目录发现扩展,并固定使用端口 34567 以便扩展自动连接。连接后应把完整输出展示给用户,并确认输出中出现 Mode: headed;若报错或 mode 不是 headed,先运行 $B status 并把输出交给用户。
源码层面,browse/src/cli.ts 中 connect 的实现印证了以上行为:它设置 BROWSE_HEADED: '1' 与 BROWSE_PORT: '34567' 启动服务器,并注释说明"使用一个众所周知的端口以便 Chrome 扩展自动连接"。同时它显式禁用父进程看门狗(watchdog)——因为 connect 模式下用户掌控着可见浏览器窗口生命周期,而 CLI 在 connect 后立即退出,若保留看门狗会在约 15 秒后误杀服务器;清理改由浏览器 disconnect 事件或 $B disconnect 触发。browse/src/browser-manager.ts 则把 token 与 port(默认 34567)安全写入 ~/.gstack/.auth.json,供后续调用鉴权。
两个保护机制值得注意(均来自 browse/src/cli.ts):
- 拒绝覆盖存活守护进程(
refuseHeadedOverLiveDaemon,issue #2219):若已有健康的 daemon 在运行,connect不会静默杀掉它(会丢失其 tabs/cookies/logins),而是报错提示先browse disconnect或显式--force-restart; - 配置哈希一致性检查(D2):状态文件中保存
(proxyUrl + headed 标志)的哈希,已有 daemon 配置与新调用不一致时同样拒绝并提示先disconnect——避免静默重启丢失会话状态。
6. Step 2:校验状态与端口
$B status
确认输出 Mode: headed,再从状态文件读取实际端口:
cat "$(git rev-parse --show-toplevel 2>/dev/null)/.gstack/browse.json" 2>/dev/null | grep -o '"port":[0-9]*' | grep -o '[0-9]*'
端口应为 34567;若不同需记录下来——用户可能要在 Side Panel 中手动输入。接着定位扩展安装路径(供后续手动加载时使用):
_EXT_PATH=""
_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
[ -n "$_ROOT" ] && [ -f "$_ROOT/.claude/skills/gstack/extension/manifest.json" ] && _EXT_PATH="$_ROOT/.claude/skills/gstack/extension"
[ -z "$_EXT_PATH" ] && [ -f "$HOME/.claude/skills/gstack/extension/manifest.json" ] && _EXT_PATH="$HOME/.claude/skills/gstack/extension"
echo "EXTENSION_PATH: ${_EXT_PATH:-NOT FOUND}"
extension/manifest.json 显示这是一个 Manifest V3 扩展 "gstack browse":side_panel.default_path 指向 sidepanel.html,background.service_worker 为 background.js,content.js/content.css 注入所有页面(负责页面叠加层与 gstack 角标);权限为 sidePanel、storage、activeTab、scripting、tabs,host 权限限定 http://127.0.0.1:*/ 与 ws://127.0.0.1:*/——即通信只走本机回环。manifest 还通过固定 key 字段钉住扩展身份(BROWSER.md 指出 v1.63 因此令既有 unpacked 安装获得新的扩展 ID,侧边面板本地状态如已存端口会重置一次)。
7. Step 3:引导用户打开 Side Panel
技能在此使用 AskUserQuestion 引导用户:
Chrome is launched with gstack control. You should see Playwright's Chromium (not your regular Chrome) with a golden shimmer line at the top of the page.
- 工具栏找拼图块图标(Extensions)——扩展加载成功时可能已显示 gstack 图标;
- 点拼图块 → 找到 gstack browse → 点 pin 图标固定;
- 点击工具栏上固定的 gstack 图标;
- 右侧 Side Panel 打开,显示实时活动流。
Port: 34567(自动探测——Playwright 托管的 Chrome 中扩展自动连接)
选项:A) 能看到 Side Panel;B) 看到 Chrome 但找不到扩展;C) 出问题了。
B 的排障路径:在地址栏输入 chrome://extensions,确认 "gstack browse" 已列出并启用;若未固定则回任意页面点拼图块固定;若完全没有列出,点 "Load unpacked",在文件选择框按 Cmd+Shift+G 粘贴 Step 2 得到的 {EXTENSION_PATH} 后选择;加载后固定并点图标打开 Side Panel;若 Side Panel 徽标仍为灰色(未连接),点 gstack 图标手动输入端口 34567。
C 的排障路径:1) 运行 $B status 查看输出;2) 服务器不健康则重跑 Step 0 清理 + Step 1 connect;3) 服务器健康但浏览器不可见则尝试 $B focus;4) 仍失败则向用户确认看到的现象(报错、白屏等)。
从安全设计看,browse/src/server.ts 中 /extension-token 端点除绑定 127.0.0.1 外还做纵深防御:解析 Host 头中的 hostname(而非拿带端口的原始头做字面比较)以抵御 DNS rebinding;扩展经该端点换取 token 后,活动流由 SSE(/activity/stream)推送,接受 Bearer token 或 30 分钟有效的 HttpOnly gstack_sse 会话 cookie(POST /sse-session 签发)——这些细节在 BROWSER.md "Side Panel + sidebar agent" 一节与 docs/designs/SIDEBAR_MESSAGE_FLOW.md 中有完整描述。
8. Step 4–5:活动流演示与侧边栏聊天
用户确认 Side Panel 工作后,跑一个快速演示:
$B goto https://news.ycombinator.com
等待 2 秒后:
$B snapshot -i
然后告诉用户:"Check the Side Panel — you should see the goto and snapshot commands appear in the activity feed. Every command Claude runs shows up here in real time."(查看 Side Panel——goto 和 snapshot 会出现在活动流中,Claude 执行的每条命令都会实时显示。)
随后介绍侧边栏聊天(Step 5):Side Panel 还有 chat 标签,输入如 "take a snapshot and describe this page" 这类消息后,一个**侧边栏 agent(子 Claude 实例)**会在浏览器中执行请求,命令实时出现在活动流里。该 agent 可导航页面、点击按钮、填写表单、读取内容,每个任务最长 5 分钟,运行在隔离会话中,不会干扰当前 Claude Code 窗口。对应实现组件见 BROWSER.md 的侧边栏架构表:extension/sidepanel.js、extension/sidepanel-terminal.js(Side Panel UI)、extension/background.js(Background SW)、extension/content.js(页面叠加层)、browse/src/terminal-agent.ts(PTY 生命周期与鉴权)。
9. Step 6:连接完成后的能力总览
技能收尾向用户说明已连上 Chrome 后可做的事:
- 实时观看 Claude 工作:运行任意 gstack 技能(
/qa、/design-review、/benchmark),每个动作都发生在可见 Chrome 窗口 + Side Panel 活动流中;无需 cookie 导入——Playwright 浏览器共享自己的会话; - 直接控制浏览器:侧边栏聊天(自然语言,由侧边栏 agent 执行,如 "fill in the login form and submit");browse 命令
$B goto <url>、$B click <sel>、$B fill <sel> <val>、$B snapshot -i——全部在 Chrome 与 Side Panel 中可见; - 窗口管理:
$B focus随时把 Chrome 带到前台;$B disconnect关闭有头 Chrome 回到 headless 模式; - 技能在 headed 模式下的表现:
/qa在可见浏览器中跑完整测试套件(每次页面加载、点击、断言都可见);/design-review在真实浏览器中截图——所见即所得;/benchmark在有头浏览器中测性能。
完成引导后,技能继续处理用户最初请求的任务;若用户未指定任务,则询问想测试或浏览什么。
10. 深入:有头模式的关键实现细节与边界
GStack Browser 是什么、不是什么。 按 BROWSER.md "Real-browser mode" 一节:它不是日常 Chrome,而是 Playwright 托管、在 Dock 与菜单栏带自定义品牌(.app 名、Dock 图标、托盘,而非 UA 字符串)的 Chromium;UA 报告底层 Chromium 版本的普通 Chrome/<version> 字符串——早期的 GStackBrowser 后缀本身就是一个高熵特征,已被移除。窗口顶部有金色微光条、右下角有悬浮 "gstack" 角标,方便分辨哪个 Chrome 窗口在被控制。
隐身补丁的边界要如实理解。 Layer C 反自动化隐身对所有 context 常开:掩盖 navigator.webdriver、恢复 window.chrome.* 形状、对齐 Notification.permission、按宿主硬件画像报告 hardwareConcurrency/deviceMemory、清扫已知 Selenium/Phantom/Playwright 全局变量、并用 Function.prototype.toString 代理让所有被补丁的 getter 报告 [native code]。但它不伪造 navigator.plugins/navigator.languages(现代指纹库会交叉校验这些字段,合成固定值反而更暴露);最底层的 CDP 协议级检测仍可能识破(BROWSER.md 明确指出 "Google can still trigger captchas")。SKILL.md 中 "sites like Google and NYTimes work without captchas" 应理解为"多数 JS 可观察的自动化特征被掩盖后许多站点可干净加载"的概括表述,而非无条件承诺。
守护进程生命周期(BROWSER.md Architecture 一节):首次调用时 CLI 在 <project>/.gstack/browse.json 找不到运行中的服务,就在后台拉起 browse/src/server.ts,随机选 10000–49151 区间端口(刻意低于 macOS 临时端口池,避免 OS 端口冲突)、生成 bearer token、以 chmod 600 写状态文件,约 3 秒完成;后续调用读状态文件、带 token POST、纯文本回显,100–200ms;30 分钟空闲自动退出;Chromium 崩溃时 daemon 立即退出(不自愈),下次调用重建;进程存活但不响应 HTTP 被视为 "busy" 而非 "dead"——CLI 给 /health 约 8 秒有界探测后才报 busy,绝不 kill 存活进程,只有显式 --force-restart 才替换(tabs/cookies/登录状态会丢失)。状态文件结构在 browse/src/cli.ts 中定义,除 port/token/pid/mode(launched|headed)外,还包括 configHash(代理/有头配置一致性)与 xvfbPid/xvfbDisplay(Linux 无 DISPLAY 时自动拉起 Xvfb 子进程,供 disconnect 时按 cmdline + 启动时间双重校验后安全清理)。
何时用有头模式(BROWSER.md 建议场景):想看着 Claude 点击应用走查的 QA 测试、需要看到 Claude 所见像素的设计评审、headless 与真实 Chrome 行为不一致的调试、屏幕共享演示,以及 pair-agent 远端代理会话。处于有头模式时,/qa、/design-review 等 CDP-aware 技能会自动跳过 cookie 导入提示与 headless 绕行——有头浏览器里已有你登录好的会话。v1.28.0.0 起还支持 --headed/--proxy(SOCKS5 走本地 127.0.0.1 认证桥)/download --navigate(浏览器原生下载)组合,以及 GSTACK_STEALTH=extended 等高级开关;这些是 daemon 启动级配置,运行中改配置会触发前述的 configHash 拒绝逻辑,需先 $B disconnect。
11. 小结与延伸阅读
/open-gstack-browser 的价值在于把 gstack 默认 headless 的浏览器操作切换为可观察、可交互、可接管的有头模式:SETUP 检查 → 预清理 → connect(固定端口 34567)→ status 校验 → Side Panel 引导与排障 → 活动流演示 → 侧边栏聊天 → 能力总览,每一步都有明确的命令、验证点和失败分支,配合 "拒绝覆盖存活 daemon""配置哈希一致性""profile 锁清理"等源码级保护,使"让 AI 在你眼皮底下操作浏览器"成为一条可复现、可排障的操作链路。
延伸阅读(均在当前仓库内):
- BROWSER.md:browse 完整参考——命令清单、快照与 @ref 选择、browser-skills 运行时、认证与 token、L1–L6 提示注入防御栈;
- open-gstack-browser/SKILL.md.tmpl:本技能的模板源(
{{PREAMBLE}}与{{BROWSE_SETUP}}占位符由bun run gen:skill-docs填充); - docs/designs/GSTACK_BROWSER_V0.md 与 docs/designs/SIDEBAR_MESSAGE_FLOW.md:GStack Browser 与侧边栏消息流的设计文档;
- browse/src/cli.ts、browse/src/browser-manager.ts、browse/src/server.ts:CLI 客户端、浏览器生命周期与守护进程服务端的实现。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00