gstack Slate Host 集成全解:逆向 OpenCode 分叉 Agent,并落地数据驱动的宿主注册表
【免费下载链接】gstackUse Garry Tan's exact Claude Code setup: 23 opinionated tools that serve as CEO, Designer, Eng Manager, Release Manager, Doc Engineer, and QA项目地址: https://gitcode.com/GitHub_Trending/gs/gstack
本文以 gstack 仓库的设计文档 SLATE_HOST.md 为主体,完整继承其中关于 Slate 逆向分析(二进制字符串证据)、技能发现机制、无头 CLI、环境变量清单与会话运行器设计的核心内容,并结合当前仓库的 hosts 注册表 与 worktree 测试隔离实现,讲清"为什么 gstack 把宿主抽象为数据驱动配置、Slate 又是如何成为一等公民宿主的"。读完后你能掌握:Slate 的目录/配置/环境变量事实边界、gstack 多宿主(host)架构的注册方式,以及如何为任意 OpenCode 分叉 Agent 编写 E2E 隔离测试。
1. Slate 是什么:一个 OpenCode 的私有分叉
设计文档对 Slate 的定位是:Random Labs 出品的专有编码 Agent CLI,其关键事实如下(均出自 docs/designs/SLATE_HOST.md 的逆向研究结论):
- 安装方式:
npm i -g @randomlabs/slate或 Homebrew(tap 路径为anthropic/tap/slate——文档特别指出这一点"值得注意":Slate 的 brew 包挂在 Anthropic 的 tap 下,而非 Random Labs 自己的)。 - 许可:专有(Proprietary)。二进制为 85MB 的编译产物(arm64/x64,覆盖 darwin/linux/windows)。
- npm 包
@randomlabs/slate@1.0.25本体仅 8.8KB,是一个"薄启动器 + 平台可选依赖"的结构。 - 多模型:动态选择 Claude Sonnet/Opus/Haiku 及其他模型。
- 设计目标是"swarm orchestration"(群体编排),支持数小时级别的长会话。
它是 OpenCode 分叉这一结论,来自对 85MB Mach-O arm64 二进制的字符串分析,证据包括:
- 二进制中直接含有字面量
name: "opencode"; - 所有
OPENCODE_*环境变量与SLATE_*等价变量并存; - 共享 OpenCode 的 tool/skill 架构、LSP 集成与终端管理;
- 但拥有自己的品牌、API 端点和配置路径。
这个结论对集成的意义在于:OpenCode 的约定大体适用,但 Slate 在其上叠加了自己的路径与环境变量——所以 gstack 不能简单复用 OpenCode 宿主的配置,而必须注册一个独立的 Slate 宿主。
2. 技能发现机制:四个目录族的扫描优先级
文档从二进制的错误信息字符串中确认了 Slate 会扫描全部四个目录族(每条错误消息都是二进制中的实证):
"failed .slate directory scan for skills" "failed .claude directory scan for skills" "failed .agents directory scan for skills" "failed .opencode directory scan for skills"发现路径(按 Slate 官方文档给出的优先级排序):
| 优先级 | 路径 | 说明 |
|---|---|---|
| 1 | .slate/skills/<name>/SKILL.md | 项目级,最高优先级 |
| 2 | ~/.slate/skills/<name>/SKILL.md | 全局 |
| 3 | .opencode/skills/、.agents/skills/ | 兼容性回退 |
| 4 | .claude/skills/ | Claude Code 兼容回退(最低) |
| 5 | slate.json中声明的自定义路径 | 用户自定义 |
配套的匹配规则与约定:
- Glob 模式:
**/SKILL.md与{skill,skills}/**/SKILL.md; - 命令(commands):目录结构相同,只是位于
commands/子目录下:.slate/commands/、.claude/commands/、.agents/commands/、.opencode/commands/; - SKILL.md frontmatter:YAML,包含
name与description两个字段,官方文档未声明长度限制。
这里藏着 gstack 集成的一个关键权衡。gstack 的 gstack 技能目录在 Claude Code 下位于.claude/skills/gstack(符号链接指向仓库根)。由于.claude/skills/是 Slate 的最低优先级兼容回退,gstack 技能"今天就能在 Slate 里工作",无需任何改动——这正是文档"What Already Works Today"一节的核心结论:安装了 gstack for Claude Code 的用户,其技能在 Slate 中同样可用。
但"可用"不等于"可靠",原因见第 7 节的SLATE_DISABLE_CLAUDE_CODE_SKILLS。
3. 项目指令与配置:CLAUDE.md 原样有效,slate.json 不代管
3.1 项目指令
Slate 同时读取CLAUDE.md和AGENTS.md作为项目指令(两个字面量均在二进制中确认)。因此 gstack 项目现有的 CLAUDE.md 在 Slate 下无需任何修改即可生效。
3.2 配置文件
Slate 的配置文件是slate.json/slate.jsonc(不是opencode.json)。官方文档列出的配置项:
privacy(boolean)——关闭遥测/日志;- 权限:按工具粒度设置
allow/ask/deny,工具包括read、edit、bash、grep、webfetch、websearch、*; - 模型槽位:
models.main、models.subagent、models.search、models.reasoning; - MCP 服务器:本地或远程,支持自定义 command 与 headers;
- 自定义命令:
/commands,支持模板。
文档在此给出了一条明确的集成边界:gstack 的 setup 脚本不应该替用户创建slate.json——权限策略属于用户自己的决策,工具链只负责投放技能文件。
4. 无头 CLI 与 Stream-JSON:会话运行器的输入侧
Slate 提供了完整的无头(headless)模式,这是 gstack 计划为其编写自动化 E2E 测试的前提:
--stream-json / --output-format stream-json JSONL 输出,官方称"与 Anthropic Claude Code SDK 兼容" --dangerously-skip-permissions 绕过所有权限检查(CI/自动化场景) --input-format stream-json 程序化输入 -q 非交互模式 -w <dir> 指定工作区目录 --output-format text 纯文本输出(默认)需要如实说明的验证边界:Stream-JSON 的"与 Claude Code SDK 兼容"是官方文档的声明,在文档写作时尚未经实证。文档的判断是:考虑到 OpenCode 血统,很可能匹配 Claude Code 的 NDJSON 事件结构(type: "assistant"、type: "tool_result"、type: "result")。因此文档留了一个显式的验证动作:在有可用额度的环境下运行slate -q "hello" --stream-json,抓取真实 JSONL 事件后,再着手构建会话运行器解析器。
4.1 会话运行器设计(文档中的规划蓝图)
文档给出的会话运行器设计要点(对应"JSONL 格式验证完成后"的实现约定):
- Spawn 命令:
slate -q "<prompt>" --stream-json --dangerously-skip-permissions -w <dir>; - 解析:Claude Code SDK 兼容的 NDJSON(假设,需验证);
- 技能投放:安装到测试夹具的
.slate/skills/(而不是.claude/skills/),以证明高优先级路径生效; - 认证:使用
SLATE_API_KEY或既有的~/.slate/凭据; - 隔离:用
SLATE_TEST_HOME重定向 home 目录; - 超时:默认 300 秒(与 Codex 运行器一致)。
文档还给出了运行器结果的结构定义:
export interface SlateResult { output: string; toolCalls: string[]; tokens: number; exitCode: number; durationMs: number; sessionId: string | null; rawLines: string[]; stderr: string; }5. 环境变量全景:44 个 SLATE_* 变量与 3 个关键开关
文档通过二进制字符串提取了完整的环境变量清单。以下为全量继承(原始分类与注释):
5.1 Slate 专属变量
| 变量 | 作用 |
|---|---|
SLATE_API_KEY | API 密钥 |
SLATE_AGENT | Agent 选择 |
SLATE_AUTO_SHARE | 自动共享设置 |
SLATE_CLIENT | 客户端标识 |
SLATE_CONFIG | 配置覆盖 |
SLATE_CONFIG_CONTENT | 内联配置 |
SLATE_CONFIG_DIR | 配置目录 |
SLATE_DANGEROUSLY_SKIP_PERMISSIONS | 绕过权限检查 |
SLATE_DIR | 数据目录覆盖 |
SLATE_DISABLE_AUTOUPDATE | 禁用自动更新 |
SLATE_DISABLE_CLAUDE_CODE | 完全禁用 Claude Code 集成 |
SLATE_DISABLE_CLAUDE_CODE_PROMPT | 禁用 Claude Code prompt 加载 |
SLATE_DISABLE_CLAUDE_CODE_SKILLS | 禁用.claude/skills/加载 |
SLATE_DISABLE_DEFAULT_PLUGINS | 禁用默认插件 |
SLATE_DISABLE_FILETIME_CHECK | 禁用文件时间检查 |
SLATE_DISABLE_LSP_DOWNLOAD | 禁用 LSP 自动下载 |
SLATE_DISABLE_MODELS_FETCH | 禁用模型配置拉取 |
SLATE_DISABLE_PROJECT_CONFIG | 禁用项目级配置 |
SLATE_DISABLE_PRUNE | 禁用会话清理 |
SLATE_DISABLE_TERMINAL_TITLE | 禁用终端标题更新 |
SLATE_ENABLE_EXA | 启用 Exa 搜索 |
SLATE_ENABLE_EXPERIMENTAL_MODELS | 启用实验性模型 |
SLATE_EXPERIMENTAL | 启用实验性功能 |
SLATE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS | bash 超时覆盖 |
SLATE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT | 禁用选中即复制 |
SLATE_EXPERIMENTAL_DISABLE_FILEWATCHER | 禁用文件监视器 |
SLATE_EXPERIMENTAL_EXA | Exa 搜索(备用开关) |
SLATE_EXPERIMENTAL_FILEWATCHER | 启用文件监视器 |
SLATE_EXPERIMENTAL_ICON_DISCOVERY | 图标发现 |
SLATE_EXPERIMENTAL_LSP_TOOL | LSP 工具 |
SLATE_EXPERIMENTAL_LSP_TY | LSP 类型检查 |
SLATE_EXPERIMENTAL_MARKDOWN | Markdown 模式 |
SLATE_EXPERIMENTAL_OUTPUT_TOKEN_MAX | 输出 token 上限 |
SLATE_EXPERIMENTAL_OXFMT | oxfmt 集成 |
SLATE_EXPERIMENTAL_PLAN_MODE | plan 模式 |
SLATE_FAKE_VCS | 测试用假 VCS |
SLATE_GIT_BASH_PATH | git bash 路径(Windows) |
SLATE_MODELS_URL | 模型配置 URL |
SLATE_PERMISSION | 权限覆盖 |
SLATE_SERVER_PASSWORD/SLATE_SERVER_USERNAME | 服务器认证 |
SLATE_TELEMETRY_DISABLED | 禁用遥测 |
SLATE_TEST_HOME | 测试用 home 目录 |
SLATE_TOKEN_DIR | token 存储目录 |
此外,npm 启动器还支持SLATE_BIN_PATH:跳过一切二进制发现逻辑,直接运行指定路径的二进制——对多版本二进制测试很有用。
5.2 OpenCode 遗留变量(仍然有效)
OPENCODE_DISABLE_LSP_DOWNLOAD、OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER、OPENCODE_EXPERIMENTAL_FILEWATCHER、OPENCODE_EXPERIMENTAL_ICON_DISCOVERY、OPENCODE_EXPERIMENTAL_LSP_TY、OPENCODE_EXPERIMENTAL_OXFMT、OPENCODE_FAKE_VCS、OPENCODE_GIT_BASH_PATH、OPENCODE_LIBC、OPENCODE_TERMINAL。
这组"仍然有效"的遗留变量,是"OpenCode 分叉"结论的另一条旁证。
5.3 对 gstack 集成至关重要的三个变量
SLATE_DISABLE_CLAUDE_CODE_SKILLS——设置后.claude/skills/加载被禁用。这使得向.slate/skills/发布技能从"优化项"变成"承重项"(load-bearing):没有原生的.slate/投放,一旦该标志被设置,gstack 技能会整体消失。SLATE_TEST_HOME——E2E 测试利器,可将 Slate 的 home 重定向到隔离临时目录,与 Codex 测试使用临时 HOME 的做法同构。SLATE_DANGEROUSLY_SKIP_PERMISSIONS——无头 E2E 测试的必需项。
由此推导出文档为 E2E 测试定下的验收标准:测试必须设置SLATE_DISABLE_CLAUDE_CODE_SKILLS=1,以此证明技能确实走了.slate/高优先级路径,而不是悄悄回退到.claude/。
6. 模型、端点与 npm 包结构
6.1 二进制中的模型引用
anthropic/claude-sonnet-4.6 anthropic/claude-opus-4 anthropic/claude-haiku-4 anthropic/slate — Slate 自己的模型路由 openai/gpt-5.3-codex google/nano-banana randomlabs/fast-default-alpha6.2 二进制中的 API 端点
api.randomlabs.ai(主 API)、api.randomlabs.ai/exaproxy(Exa 搜索代理)、agent-worker-prod.randomlabs.workers.dev(生产 worker)、agent-worker-dev.randomlabs.workers.dev(开发 worker)、dashboard.randomlabs.ai(控制台)、docs.randomlabs.ai(文档)、randomlabs.ai/config.json(远程配置)。
6.3 npm 包结构
@randomlabs/slate (8.8 kB, 薄启动器) ├── bin/slate — Node.js 启动器(在 node_modules 中定位平台二进制) ├── bin/slate1 — Bun 启动器(同逻辑,用 import.meta.filename) ├── postinstall.mjs — 校验平台二进制存在,必要时建符号链接 └── package.json — 声明所有平台的 optionalDependencies 平台包(各约 85MB): ├── @randomlabs/slate-darwin-arm64 / slate-darwin-x64 ├── @randomlabs/slate-linux-arm64 / slate-linux-x64 ├── @randomlabs/slate-linux-x64-musl / slate-linux-arm64-musl ├── @randomlabs/slate-linux-x64-baseline / slate-linux-x64-baseline-musl ├── @randomlabs/slate-darwin-x64-baseline └── @randomlabs/slate-windows-x64 / slate-windows-x64-baseline7. 从"被阻塞"到"已落地":数据驱动的宿主注册表
设计文档的落点是一个架构问题。文档当时的状态是"Research complete,blocked on host config refactor":外部评审(Codex outside voice)指出,在 Claude、Codex、Factory 之后再加第 4 个宿主 Slate,属于"为一条路径别名做宿主爆炸"——当时的架构存在硬编码宿主联合类型、transformFrontmatter()里的近重复 per-host 分支、EXTERNAL_HOST_CONFIG的重复配置模式、setup 脚本中的 per-host 函数等一整套需要为 Slate 复制一遍的模式。文档的结论是:把宿主重构为数据驱动(配置对象而非 if/else 分支)后,Slate 集成将变得平凡,未来任何新 OpenCode 分叉/新 Agent 都是零成本。
当前仓库的源码结构显示,这次重构方向已经被执行,Slate 已作为一等宿主注册:
- 宿主即数据:hosts/define-host.ts 中的
defineHost()工厂是所有宿主的唯一构造点。文件头注释直白地说明了动机——"defineHost() factory — the single place the copy-paste across hosts/*.ts used to live"。每个宿主不覆盖的字段都拿到通用外部宿主默认值:路径从宿主名派生(.{name}/skills/gstack)、frontmatter 白名单只保留name+description(恰与第 2 节 Slate 的 frontmatter 约定一致)、标准三组 pathRewrite(~/.claude/skills/gstack→ 全局根、.claude/skills/gstack→ 本地技能根、.claude/skills→{hostSubdir}/skills)、共享 runtimeRoot 资产清单、符号链接式安装。 - Slate 宿主定义极简:hosts/slate.ts 全文只有 6 行有效代码——
defineHost({ name: 'slate', displayName: 'Slate' }),其余全部继承默认值。这正是文档预言的"集成变得平凡"的实证;对比 hosts/opencode.ts 需要覆盖 XDG 全局根与更宽的 runtimeRoot 资产集,可见只有真实差异才需要覆盖项。 - 注册表即唯一事实源:hosts/index.ts 的
ALL_HOST_CONFIGS目前登记了 10 个宿主(claude、codex、factory、kiro、opencode、slate、cursor、openclaw、hermes、gbrain),Host联合类型、宿主名数组、别名解析(resolveHostArg)全部从该数组派生——文件注释给出的加宿主流程只有两步:"create hosts/myhost.ts, import here, add to ALL_HOST_CONFIGS"。 - 安装入口打通:
setup脚本的--host参数校验列表中已包含slate(claude|codex|kiro|factory|opencode|cursor|slate|auto等,见 setup 第 180 行附近的参数解析与第 233 行的取值校验),即./setup --host slate是文档中"setup 脚本自动探测 slate 二进制、把技能装到~/.slate/skills/"这一规划项在命令行侧的落点。 - worktree 隔离测试的缺口已补齐:文档"Missing from the plan"一节曾指出 lib/worktree.ts 只复制
.agents/、不复制.slate/,worktree 里的 E2E 测试拿不到 Slate 技能。当前实现(lib/worktree.ts)已改为遍历所有外部宿主的hostSubdir并逐一复制进 worktree,且复制逻辑会跳过符号链接(例如.claude/skills/gstack指向仓库根的链接)——.slate/是否被复制完全由宿主注册表驱动,无需为 Slate 写任何特判。 - 文档生成链路已认得 Slate:scripts/gen-skill-docs.ts 的注释中把 slate 与其他宿主并列为"静态抑制 GBrain 解析器"的宿主之一,说明按宿主生成 SKILL.md 文档的管线已把 Slate 纳入统一处理。
- 文档还提到旧
bin/gstack-platform-detect已被删除,宿主探测改由hosts/注册表承载,并经 scripts/host-config-export.ts 导出给 shell 脚本——当前仓库的hosts/目录结构印证了这一说法(hosts/下有 claude、codex、cursor、factory、gbrain、hermes、kiro、openclaw、opencode、slate 各自的.ts定义)。
值得说明的时序关系:设计文档记录的是 2026-04-02 的调研时点与分支garrytan/slate-agent-support的状态("blocked on host config refactor");当前仓库快照中注册表架构与 Slate 宿主均已就位。两相对照,恰好完整展示了"gstack 如何用一个工厂 + 注册表把第 10 个宿主压缩成 6 行代码"的演进路径。
8. 一等支持带来的增益(文档结论全量继承)
综合全篇,"一等公民支持"相对"今天已可用"的增量,文档归纳为四条:
- 可靠性——
.slate/skills/是 Slate 的最高优先级路径,且不受SLATE_DISABLE_CLAUDE_CODE_SKILLS影响; - 优化的 frontmatter——剥离 Claude 专属字段(
allowed-tools、hooks、version),只保留 Slate 实际使用的name与description(这一点已被defineHost()的默认 frontmatter 策略实现); - setup 脚本——自动探测
slate二进制,把技能安装到~/.slate/skills/; - E2E 测试——验证技能在被 Slate 直接调用时确实工作,且必须按第 5.3 节的标准设置
SLATE_DISABLE_CLAUDE_CODE_SKILLS=1排除回退路径的干扰。
9. 关键事实与适用前提小结
- 本文所有关于 Slate 的事实(目录族、优先级、glob 模式、环境变量、模型引用、端点、npm 结构)均来自 docs/designs/SLATE_HOST.md 记录的二进制字符串分析与官方文档转述,其中 Stream-JSON 与 Claude Code SDK 的兼容性在文档写作时尚未实证,引用时应保留该限定;
- 仓库侧的实现事实以当前快照为准:Slate 宿主位于 hosts/slate.ts,注册于 hosts/index.ts,worktree 复制逻辑见 lib/worktree.ts,安装入口见 setup 的
--host参数; - 若你要为任意新的 OpenCode 分叉 Agent 接入 gstack,操作路径即 hosts/index.ts 顶部注释给出的三步:新建
hosts/<name>.ts、在ALL_HOST_CONFIGS注册、让 setup 的宿主校验列表接纳新名字——frontmatter 白名单、路径重写、runtimeRoot 资产与 worktree 复制都会从注册表自动生效。
【免费下载链接】gstackUse Garry Tan's exact Claude Code setup: 23 opinionated tools that serve as CEO, Designer, Eng Manager, Release Manager, Doc Engineer, and QA项目地址: https://gitcode.com/GitHub_Trending/gs/gstack
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考