~cytrogen/gstack

ref: 9c5f479745acc90533a7ff75a00771b9056c43ef gstack/docs/designs/SLATE_HOST.md -rw-r--r-- 12.6 KiB
9c5f4797 — Cytrogen fork: 频率分级路由 + 触发式描述符重写 3 days ago

#Slate Host Integration — Research & Design Doc

Date: 2026-04-02 Branch: garrytan/slate-agent-support Status: Research complete, blocked on host config refactor Supersedes: None

#What is Slate

Slate is a proprietary coding agent CLI from Random Labs. Install: npm i -g @randomlabs/slate or brew install anthropic/tap/slate. License: Proprietary. 85MB compiled Bun binary (arm64/x64, darwin/linux/windows). npm package: @randomlabs/slate@1.0.25 (thin 8.8KB launcher + platform-specific optional deps).

Multi-model: dynamically selects Claude Sonnet/Opus/Haiku, plus other models. Built for "swarm orchestration" with extended multi-hour sessions.

#Slate is an OpenCode fork

Confirmed via binary strings analysis of the 85MB Mach-O arm64 binary:

  • Internal name: name: "opencode" (literal string in binary)
  • All OPENCODE_* env vars present alongside SLATE_* equivalents
  • Shares OpenCode's tool/skill architecture, LSP integration, terminal management
  • Own branding, API endpoints (api.randomlabs.ai, agent-worker-prod.randomlabs.workers.dev), and config paths

This matters for integration: OpenCode conventions mostly apply, but Slate adds its own paths and env vars on top.

#Skill Discovery (confirmed from binary)

Slate scans ALL four directory families for skills. Error messages in binary confirm:

"failed .slate directory scan for skills"
"failed .claude directory scan for skills"
"failed .agents directory scan for skills"
"failed .opencode directory scan for skills"

Discovery paths (priority order from Slate docs):

  1. .slate/skills/<name>/SKILL.md — project-level, highest priority
  2. ~/.slate/skills/<name>/SKILL.md — global
  3. .opencode/skills/, .agents/skills/ — compatibility fallback
  4. .claude/skills/ — Claude Code compatibility fallback (lowest)
  5. Custom paths via slate.json

Glob patterns: **/SKILL.md and {skill,skills}/**/SKILL.md

Commands: Same directory structure but under commands/ subdirs: /.slate/commands/, /.claude/commands/, /.agents/commands/, /.opencode/commands/

Skill frontmatter: YAML with name and description fields (per Slate docs). No documented length limits on either field.

#Project Instructions

Slate reads both CLAUDE.md and AGENTS.md for project instructions. Both literal strings confirmed in binary. No changes needed to existing gstack projects... CLAUDE.md works as-is.

#Configuration

Config file: slate.json / slate.jsonc (NOT opencode.json)

Config options (from Slate docs):

  • privacy (boolean) — disables telemetry/logging
  • Permissions: allow, ask, deny per tool (read, edit, bash, grep, webfetch, websearch, *)
  • Model slots: models.main, models.subagent, models.search, models.reasoning
  • MCP servers: local or remote with custom commands and headers
  • Custom commands: /commands with templates

The setup script should NOT create slate.json. Users configure their own permissions.

#CLI Flags (Headless Mode)

--stream-json / --output-format stream-json  — JSONL output, "compatible with Anthropic Claude Code SDK"
--dangerously-skip-permissions               — bypass all permission checks (CI/automation)
--input-format stream-json                   — programmatic input
-q                                           — non-interactive mode
-w <dir>                                     — workspace directory
--output-format text                         — plain text output (default)

Stream-JSON format: Slate docs claim "compatible with Anthropic Claude Code SDK." Not yet empirically verified. Given OpenCode heritage, likely matches Claude Code's NDJSON event schema (type: "assistant", type: "tool_result", type: "result").

Need to verify: Run slate -q "hello" --stream-json with valid credits and capture actual JSONL events before building the session runner parser.

#Environment Variables (from binary strings)

#Slate-specific

SLATE_API_KEY                              — API key
SLATE_AGENT                                — agent selection
SLATE_AUTO_SHARE                           — auto-share setting
SLATE_CLIENT                               — client identifier
SLATE_CONFIG                               — config override
SLATE_CONFIG_CONTENT                       — inline config
SLATE_CONFIG_DIR                           — config directory
SLATE_DANGEROUSLY_SKIP_PERMISSIONS         — bypass permissions
SLATE_DIR                                  — data directory override
SLATE_DISABLE_AUTOUPDATE                   — disable auto-update
SLATE_DISABLE_CLAUDE_CODE                  — disable Claude Code integration entirely
SLATE_DISABLE_CLAUDE_CODE_PROMPT           — disable Claude Code prompt loading
SLATE_DISABLE_CLAUDE_CODE_SKILLS           — disable .claude/skills/ loading
SLATE_DISABLE_DEFAULT_PLUGINS              — disable default plugins
SLATE_DISABLE_FILETIME_CHECK               — disable file time checks
SLATE_DISABLE_LSP_DOWNLOAD                 — disable LSP auto-download
SLATE_DISABLE_MODELS_FETCH                 — disable models config fetch
SLATE_DISABLE_PROJECT_CONFIG               — disable project-level config
SLATE_DISABLE_PRUNE                        — disable session pruning
SLATE_DISABLE_TERMINAL_TITLE               — disable terminal title updates
SLATE_ENABLE_EXA                           — enable Exa search
SLATE_ENABLE_EXPERIMENTAL_MODELS           — enable experimental models
SLATE_EXPERIMENTAL                         — enable experimental features
SLATE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS — bash timeout override
SLATE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT  — disable copy on select
SLATE_EXPERIMENTAL_DISABLE_FILEWATCHER     — disable file watcher
SLATE_EXPERIMENTAL_EXA                     — Exa search (alt flag)
SLATE_EXPERIMENTAL_FILEWATCHER             — enable file watcher
SLATE_EXPERIMENTAL_ICON_DISCOVERY          — icon discovery
SLATE_EXPERIMENTAL_LSP_TOOL               — LSP tool
SLATE_EXPERIMENTAL_LSP_TY                 — LSP type checking
SLATE_EXPERIMENTAL_MARKDOWN               — markdown mode
SLATE_EXPERIMENTAL_OUTPUT_TOKEN_MAX       — output token limit
SLATE_EXPERIMENTAL_OXFMT                  — oxfmt integration
SLATE_EXPERIMENTAL_PLAN_MODE              — plan mode
SLATE_FAKE_VCS                            — fake VCS for testing
SLATE_GIT_BASH_PATH                       — git bash path (Windows)
SLATE_MODELS_URL                          — models config URL
SLATE_PERMISSION                          — permission override
SLATE_SERVER_PASSWORD                     — server auth
SLATE_SERVER_USERNAME                     — server auth
SLATE_TELEMETRY_DISABLED                  — disable telemetry
SLATE_TEST_HOME                           — test home directory
SLATE_TOKEN_DIR                           — token storage directory

#OpenCode legacy (still functional)

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

#Critical env vars for gstack integration

SLATE_DISABLE_CLAUDE_CODE_SKILLS — When set, .claude/skills/ loading is disabled. This makes publishing to .slate/skills/ load-bearing, not just an optimization. Without native .slate/ publishing, gstack skills vanish when this flag is set.

SLATE_TEST_HOME — Useful for E2E tests. Can redirect Slate's home directory to an isolated temp directory, similar to how Codex tests use a temp HOME.

SLATE_DANGEROUSLY_SKIP_PERMISSIONS — Required for headless E2E tests.

#Model References (from binary)

anthropic/claude-sonnet-4.6
anthropic/claude-opus-4
anthropic/claude-haiku-4
anthropic/slate              — Slate's own model routing
openai/gpt-5.3-codex
google/nano-banana
randomlabs/fast-default-alpha

#API Endpoints (from binary)

https://api.randomlabs.ai                          — main API
https://api.randomlabs.ai/exaproxy                 — Exa search proxy
https://agent-worker-prod.randomlabs.workers.dev   — production worker
https://agent-worker-dev.randomlabs.workers.dev    — dev worker
https://dashboard.randomlabs.ai                    — dashboard
https://docs.randomlabs.ai                         — documentation
https://randomlabs.ai/config.json                  — remote config

Brew tap: anthropic/tap/slate (notable: under Anthropic's tap, not Random Labs)

#npm Package Structure

@randomlabs/slate (8.8 kB, thin launcher)
├── bin/slate           — Node.js launcher (finds platform binary in node_modules)
├── bin/slate1          — Bun launcher (same logic, import.meta.filename)
├── postinstall.mjs     — Verifies platform binary exists, symlinks if needed
└── package.json        — Declares optionalDependencies for all platforms

Platform packages (85MB each):
├── @randomlabs/slate-darwin-arm64
├── @randomlabs/slate-darwin-x64
├── @randomlabs/slate-linux-arm64
├── @randomlabs/slate-linux-x64
├── @randomlabs/slate-linux-x64-musl
├── @randomlabs/slate-linux-arm64-musl
├── @randomlabs/slate-linux-x64-baseline
├── @randomlabs/slate-linux-x64-baseline-musl
├── @randomlabs/slate-darwin-x64-baseline
├── @randomlabs/slate-windows-x64
└── @randomlabs/slate-windows-x64-baseline

Binary override: SLATE_BIN_PATH env var skips all discovery, runs the specified binary directly.

#What Already Works Today

gstack skills already work in Slate via the .claude/skills/ fallback path. No changes needed for basic functionality. Users who install gstack for Claude Code and also use Slate will find their skills available in both agents.

#What First-Class Support Adds

  1. Reliability.slate/skills/ is Slate's highest-priority path. Immune to SLATE_DISABLE_CLAUDE_CODE_SKILLS.
  2. Optimized frontmatter — Strip Claude-specific fields (allowed-tools, hooks, version) that Slate doesn't use. Keep only name and description.
  3. Setup script — Auto-detect slate binary, install skills to ~/.slate/skills/.
  4. E2E tests — Verify skills work when invoked by Slate directly.

#Blocked On: Host Config Refactor

Codex's outside voice review identified that adding Slate as a 4th host (after Claude, Codex, Factory) is "host explosion for a path alias." The current architecture has:

  • Hard-coded host names in type Host = 'claude' | 'codex' | 'factory'
  • Per-host branches in transformFrontmatter() with near-duplicate logic
  • Per-host config in EXTERNAL_HOST_CONFIG with similar patterns
  • Per-host functions in the setup script (create_codex_runtime_root, link_codex_skill_dirs)
  • Host names duplicated in bin/gstack-platform-detect, bin/gstack-uninstall, bin/dev-setup

Adding Slate means copying all of these patterns again. A refactor to make hosts data-driven (config objects instead of if/else branches) would make Slate integration trivial AND make future hosts (any new OpenCode fork, any new agent) zero-effort.

#Missing from the plan (identified by Codex)

  • lib/worktree.ts only copies .agents/, not .slate/ — E2E tests in worktrees won't have Slate skills
  • bin/gstack-uninstall doesn't know about .slate/
  • bin/dev-setup doesn't wire .slate/ for contributor dev mode
  • bin/gstack-platform-detect doesn't detect Slate
  • E2E tests should set SLATE_DISABLE_CLAUDE_CODE_SKILLS=1 to prove .slate/ path actually works (not just falling back to .claude/)

#Session Runner Design (for later)

When the JSONL format is verified, the session runner should:

  • Spawn: slate -q "<prompt>" --stream-json --dangerously-skip-permissions -w <dir>
  • Parse: Claude Code SDK-compatible NDJSON (assumed, needs verification)
  • Skills: Install to .slate/skills/ in test fixture (not .claude/skills/)
  • Auth: Use SLATE_API_KEY or existing ~/.slate/ credentials
  • Isolation: Use SLATE_TEST_HOME for home directory isolation
  • Timeout: 300s default (same as Codex)
export interface SlateResult {
  output: string;
  toolCalls: string[];
  tokens: number;
  exitCode: number;
  durationMs: number;
  sessionId: string | null;
  rawLines: string[];
  stderr: string;
}

#Docs References