Skip to content

Commit 103a1b3

Browse files
garrytanclaude
andauthored
docs: Slate agent integration research + design doc (garrytan#782)
Comprehensive research on Slate (Random Labs) as a potential first-class coding agent host. Includes binary analysis findings, skill discovery paths, env vars, CLI flags, and npm package structure. Blocked on host config refactor before implementation. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent c620de3 commit 103a1b3

File tree

1 file changed

+290
-0
lines changed

1 file changed

+290
-0
lines changed

docs/designs/SLATE_HOST.md

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
# Slate Host Integration — Research & Design Doc
2+
3+
**Date:** 2026-04-02
4+
**Branch:** garrytan/slate-agent-support
5+
**Status:** Research complete, blocked on host config refactor
6+
**Supersedes:** None
7+
8+
## What is Slate
9+
10+
Slate is a proprietary coding agent CLI from Random Labs.
11+
Install: `npm i -g @randomlabs/slate` or `brew install anthropic/tap/slate`.
12+
License: Proprietary. 85MB compiled Bun binary (arm64/x64, darwin/linux/windows).
13+
npm package: `@randomlabs/slate@1.0.25` (thin 8.8KB launcher + platform-specific optional deps).
14+
15+
Multi-model: dynamically selects Claude Sonnet/Opus/Haiku, plus other models.
16+
Built for "swarm orchestration" with extended multi-hour sessions.
17+
18+
## Slate is an OpenCode fork
19+
20+
**Confirmed via binary strings analysis** of the 85MB Mach-O arm64 binary:
21+
22+
- Internal name: `name: "opencode"` (literal string in binary)
23+
- All `OPENCODE_*` env vars present alongside `SLATE_*` equivalents
24+
- Shares OpenCode's tool/skill architecture, LSP integration, terminal management
25+
- Own branding, API endpoints (`api.randomlabs.ai`, `agent-worker-prod.randomlabs.workers.dev`), and config paths
26+
27+
This matters for integration: OpenCode conventions mostly apply, but Slate adds
28+
its own paths and env vars on top.
29+
30+
## Skill Discovery (confirmed from binary)
31+
32+
Slate scans ALL four directory families for skills. Error messages in binary confirm:
33+
34+
```
35+
"failed .slate directory scan for skills"
36+
"failed .claude directory scan for skills"
37+
"failed .agents directory scan for skills"
38+
"failed .opencode directory scan for skills"
39+
```
40+
41+
**Discovery paths (priority order from Slate docs):**
42+
43+
1. `.slate/skills/<name>/SKILL.md` — project-level, highest priority
44+
2. `~/.slate/skills/<name>/SKILL.md` — global
45+
3. `.opencode/skills/`, `.agents/skills/` — compatibility fallback
46+
4. `.claude/skills/` — Claude Code compatibility fallback (lowest)
47+
5. Custom paths via `slate.json`
48+
49+
**Glob patterns:** `**/SKILL.md` and `{skill,skills}/**/SKILL.md`
50+
51+
**Commands:** Same directory structure but under `commands/` subdirs:
52+
`/.slate/commands/`, `/.claude/commands/`, `/.agents/commands/`, `/.opencode/commands/`
53+
54+
**Skill frontmatter:** YAML with `name` and `description` fields (per Slate docs).
55+
No documented length limits on either field.
56+
57+
## Project Instructions
58+
59+
Slate reads both `CLAUDE.md` and `AGENTS.md` for project instructions.
60+
Both literal strings confirmed in binary. No changes needed to existing
61+
gstack projects... CLAUDE.md works as-is.
62+
63+
## Configuration
64+
65+
**Config file:** `slate.json` / `slate.jsonc` (NOT opencode.json)
66+
67+
**Config options (from Slate docs):**
68+
- `privacy` (boolean) — disables telemetry/logging
69+
- Permissions: `allow`, `ask`, `deny` per tool (`read`, `edit`, `bash`, `grep`, `webfetch`, `websearch`, `*`)
70+
- Model slots: `models.main`, `models.subagent`, `models.search`, `models.reasoning`
71+
- MCP servers: local or remote with custom commands and headers
72+
- Custom commands: `/commands` with templates
73+
74+
The setup script should NOT create `slate.json`. Users configure their own permissions.
75+
76+
## CLI Flags (Headless Mode)
77+
78+
```
79+
--stream-json / --output-format stream-json — JSONL output, "compatible with Anthropic Claude Code SDK"
80+
--dangerously-skip-permissions — bypass all permission checks (CI/automation)
81+
--input-format stream-json — programmatic input
82+
-q — non-interactive mode
83+
-w <dir> — workspace directory
84+
--output-format text — plain text output (default)
85+
```
86+
87+
**Stream-JSON format:** Slate docs claim "compatible with Anthropic Claude Code SDK."
88+
Not yet empirically verified. Given OpenCode heritage, likely matches Claude Code's
89+
NDJSON event schema (type: "assistant", type: "tool_result", type: "result").
90+
91+
**Need to verify:** Run `slate -q "hello" --stream-json` with valid credits and
92+
capture actual JSONL events before building the session runner parser.
93+
94+
## Environment Variables (from binary strings)
95+
96+
### Slate-specific
97+
```
98+
SLATE_API_KEY — API key
99+
SLATE_AGENT — agent selection
100+
SLATE_AUTO_SHARE — auto-share setting
101+
SLATE_CLIENT — client identifier
102+
SLATE_CONFIG — config override
103+
SLATE_CONFIG_CONTENT — inline config
104+
SLATE_CONFIG_DIR — config directory
105+
SLATE_DANGEROUSLY_SKIP_PERMISSIONS — bypass permissions
106+
SLATE_DIR — data directory override
107+
SLATE_DISABLE_AUTOUPDATE — disable auto-update
108+
SLATE_DISABLE_CLAUDE_CODE — disable Claude Code integration entirely
109+
SLATE_DISABLE_CLAUDE_CODE_PROMPT — disable Claude Code prompt loading
110+
SLATE_DISABLE_CLAUDE_CODE_SKILLS — disable .claude/skills/ loading
111+
SLATE_DISABLE_DEFAULT_PLUGINS — disable default plugins
112+
SLATE_DISABLE_FILETIME_CHECK — disable file time checks
113+
SLATE_DISABLE_LSP_DOWNLOAD — disable LSP auto-download
114+
SLATE_DISABLE_MODELS_FETCH — disable models config fetch
115+
SLATE_DISABLE_PROJECT_CONFIG — disable project-level config
116+
SLATE_DISABLE_PRUNE — disable session pruning
117+
SLATE_DISABLE_TERMINAL_TITLE — disable terminal title updates
118+
SLATE_ENABLE_EXA — enable Exa search
119+
SLATE_ENABLE_EXPERIMENTAL_MODELS — enable experimental models
120+
SLATE_EXPERIMENTAL — enable experimental features
121+
SLATE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS — bash timeout override
122+
SLATE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT — disable copy on select
123+
SLATE_EXPERIMENTAL_DISABLE_FILEWATCHER — disable file watcher
124+
SLATE_EXPERIMENTAL_EXA — Exa search (alt flag)
125+
SLATE_EXPERIMENTAL_FILEWATCHER — enable file watcher
126+
SLATE_EXPERIMENTAL_ICON_DISCOVERY — icon discovery
127+
SLATE_EXPERIMENTAL_LSP_TOOL — LSP tool
128+
SLATE_EXPERIMENTAL_LSP_TY — LSP type checking
129+
SLATE_EXPERIMENTAL_MARKDOWN — markdown mode
130+
SLATE_EXPERIMENTAL_OUTPUT_TOKEN_MAX — output token limit
131+
SLATE_EXPERIMENTAL_OXFMT — oxfmt integration
132+
SLATE_EXPERIMENTAL_PLAN_MODE — plan mode
133+
SLATE_FAKE_VCS — fake VCS for testing
134+
SLATE_GIT_BASH_PATH — git bash path (Windows)
135+
SLATE_MODELS_URL — models config URL
136+
SLATE_PERMISSION — permission override
137+
SLATE_SERVER_PASSWORD — server auth
138+
SLATE_SERVER_USERNAME — server auth
139+
SLATE_TELEMETRY_DISABLED — disable telemetry
140+
SLATE_TEST_HOME — test home directory
141+
SLATE_TOKEN_DIR — token storage directory
142+
```
143+
144+
### OpenCode legacy (still functional)
145+
```
146+
OPENCODE_DISABLE_LSP_DOWNLOAD
147+
OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER
148+
OPENCODE_EXPERIMENTAL_FILEWATCHER
149+
OPENCODE_EXPERIMENTAL_ICON_DISCOVERY
150+
OPENCODE_EXPERIMENTAL_LSP_TY
151+
OPENCODE_EXPERIMENTAL_OXFMT
152+
OPENCODE_FAKE_VCS
153+
OPENCODE_GIT_BASH_PATH
154+
OPENCODE_LIBC
155+
OPENCODE_TERMINAL
156+
```
157+
158+
### Critical env vars for gstack integration
159+
160+
**`SLATE_DISABLE_CLAUDE_CODE_SKILLS`** — When set, `.claude/skills/` loading is disabled.
161+
This makes publishing to `.slate/skills/` load-bearing, not just an optimization.
162+
Without native `.slate/` publishing, gstack skills vanish when this flag is set.
163+
164+
**`SLATE_TEST_HOME`** — Useful for E2E tests. Can redirect Slate's home directory
165+
to an isolated temp directory, similar to how Codex tests use a temp HOME.
166+
167+
**`SLATE_DANGEROUSLY_SKIP_PERMISSIONS`** — Required for headless E2E tests.
168+
169+
## Model References (from binary)
170+
171+
```
172+
anthropic/claude-sonnet-4.6
173+
anthropic/claude-opus-4
174+
anthropic/claude-haiku-4
175+
anthropic/slate — Slate's own model routing
176+
openai/gpt-5.3-codex
177+
google/nano-banana
178+
randomlabs/fast-default-alpha
179+
```
180+
181+
## API Endpoints (from binary)
182+
183+
```
184+
https://api.randomlabs.ai — main API
185+
https://api.randomlabs.ai/exaproxy — Exa search proxy
186+
https://agent-worker-prod.randomlabs.workers.dev — production worker
187+
https://agent-worker-dev.randomlabs.workers.dev — dev worker
188+
https://dashboard.randomlabs.ai — dashboard
189+
https://docs.randomlabs.ai — documentation
190+
https://randomlabs.ai/config.json — remote config
191+
```
192+
193+
Brew tap: `anthropic/tap/slate` (notable: under Anthropic's tap, not Random Labs)
194+
195+
## npm Package Structure
196+
197+
```
198+
@randomlabs/slate (8.8 kB, thin launcher)
199+
├── bin/slate — Node.js launcher (finds platform binary in node_modules)
200+
├── bin/slate1 — Bun launcher (same logic, import.meta.filename)
201+
├── postinstall.mjs — Verifies platform binary exists, symlinks if needed
202+
└── package.json — Declares optionalDependencies for all platforms
203+
204+
Platform packages (85MB each):
205+
├── @randomlabs/slate-darwin-arm64
206+
├── @randomlabs/slate-darwin-x64
207+
├── @randomlabs/slate-linux-arm64
208+
├── @randomlabs/slate-linux-x64
209+
├── @randomlabs/slate-linux-x64-musl
210+
├── @randomlabs/slate-linux-arm64-musl
211+
├── @randomlabs/slate-linux-x64-baseline
212+
├── @randomlabs/slate-linux-x64-baseline-musl
213+
├── @randomlabs/slate-darwin-x64-baseline
214+
├── @randomlabs/slate-windows-x64
215+
└── @randomlabs/slate-windows-x64-baseline
216+
```
217+
218+
Binary override: `SLATE_BIN_PATH` env var skips all discovery, runs the specified binary directly.
219+
220+
## What Already Works Today
221+
222+
gstack skills already work in Slate via the `.claude/skills/` fallback path.
223+
No changes needed for basic functionality. Users who install gstack for Claude Code
224+
and also use Slate will find their skills available in both agents.
225+
226+
## What First-Class Support Adds
227+
228+
1. **Reliability**`.slate/skills/` is Slate's highest-priority path. Immune to
229+
`SLATE_DISABLE_CLAUDE_CODE_SKILLS`.
230+
2. **Optimized frontmatter** — Strip Claude-specific fields (allowed-tools, hooks, version)
231+
that Slate doesn't use. Keep only `name` and `description`.
232+
3. **Setup script** — Auto-detect `slate` binary, install skills to `~/.slate/skills/`.
233+
4. **E2E tests** — Verify skills work when invoked by Slate directly.
234+
235+
## Blocked On: Host Config Refactor
236+
237+
Codex's outside voice review identified that adding Slate as a 4th host (after Claude,
238+
Codex, Factory) is "host explosion for a path alias." The current architecture has:
239+
240+
- Hard-coded host names in `type Host = 'claude' | 'codex' | 'factory'`
241+
- Per-host branches in `transformFrontmatter()` with near-duplicate logic
242+
- Per-host config in `EXTERNAL_HOST_CONFIG` with similar patterns
243+
- Per-host functions in the setup script (`create_codex_runtime_root`, `link_codex_skill_dirs`)
244+
- Host names duplicated in `bin/gstack-platform-detect`, `bin/gstack-uninstall`, `bin/dev-setup`
245+
246+
Adding Slate means copying all of these patterns again. A refactor to make hosts
247+
data-driven (config objects instead of if/else branches) would make Slate integration
248+
trivial AND make future hosts (any new OpenCode fork, any new agent) zero-effort.
249+
250+
### Missing from the plan (identified by Codex)
251+
252+
- `lib/worktree.ts` only copies `.agents/`, not `.slate/` — E2E tests in worktrees won't
253+
have Slate skills
254+
- `bin/gstack-uninstall` doesn't know about `.slate/`
255+
- `bin/dev-setup` doesn't wire `.slate/` for contributor dev mode
256+
- `bin/gstack-platform-detect` doesn't detect Slate
257+
- E2E tests should set `SLATE_DISABLE_CLAUDE_CODE_SKILLS=1` to prove `.slate/` path
258+
actually works (not just falling back to `.claude/`)
259+
260+
## Session Runner Design (for later)
261+
262+
When the JSONL format is verified, the session runner should:
263+
264+
- Spawn: `slate -q "<prompt>" --stream-json --dangerously-skip-permissions -w <dir>`
265+
- Parse: Claude Code SDK-compatible NDJSON (assumed, needs verification)
266+
- Skills: Install to `.slate/skills/` in test fixture (not `.claude/skills/`)
267+
- Auth: Use `SLATE_API_KEY` or existing `~/.slate/` credentials
268+
- Isolation: Use `SLATE_TEST_HOME` for home directory isolation
269+
- Timeout: 300s default (same as Codex)
270+
271+
```typescript
272+
export interface SlateResult {
273+
output: string;
274+
toolCalls: string[];
275+
tokens: number;
276+
exitCode: number;
277+
durationMs: number;
278+
sessionId: string | null;
279+
rawLines: string[];
280+
stderr: string;
281+
}
282+
```
283+
284+
## Docs References
285+
286+
- Slate docs: https://docs.randomlabs.ai
287+
- Quickstart: https://docs.randomlabs.ai/en/getting-started/quickstart
288+
- Skills: https://docs.randomlabs.ai/en/using-slate/skills
289+
- Configuration: https://docs.randomlabs.ai/en/using-slate/configuration
290+
- Hotkeys: https://docs.randomlabs.ai/en/using-slate/hotkey_reference

0 commit comments

Comments
 (0)