Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

gstack Administrator & Developer Guide

Generated May 2026 from garrytan/gstack at e3d7f49

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

gstack (Garry's Stack) is an all-in-one AI engineering toolkit built on Bun, providing headless browser automation, AI-powered design generation, PDF rendering, and 30+ Claude Code slash-command skills. This guide covers architecture, configuration, deployment, security, and developer internals for administrators and contributors working with gstack v1.10.1.0.


1. Architecture Overview

1.1 System Design

gstack is organized as a monorepo with four primary subsystems that share a common Bun runtime:

┌─────────────────────────────────────────────────────────────┐
│                        gstack CLI                           │
│  browse/src/cli.ts → HTTP → browse/src/server.ts (Bun)     │
│                              ├── BrowserManager (Playwright)│
│                              ├── Security Classifier        │
│                              ├── Activity Stream (SSE)      │
│                              ├── Token Registry (multi-agent)│
│                              └── Sidebar Agent (Claude)      │
├─────────────────────────────────────────────────────────────┤
│  design/src/cli.ts → OpenAI GPT-4o Image API               │
│  make-pdf/src/cli.ts → browse CLI → Chromium PDF           │
├─────────────────────────────────────────────────────────────┤
│  Skills System                                               │
│  ├── SKILL.md.tmpl (templates with resolver placeholders)    │
│  ├── scripts/resolvers/ (dynamic content generators)         │
│  ├── scripts/gen-skill-docs.ts (multi-host doc generation)   │
│  └── hosts/ (per-host config: path rewrites, frontmatter)    │
├─────────────────────────────────────────────────────────────┤
│  Supabase Backend                                            │
│  ├── telemetry-ingest (edge function)                        │
│  ├── community-pulse (edge function, cached)                 │
│  ├── update-check (edge function)                            │
│  └── Migrations (001-004): telemetry, RLS, upsert, attack   │
├─────────────────────────────────────────────────────────────┤
│  Chrome Extension                                            │
│  ├── background.js (health polling, command proxy, refs)     │
│  ├── sidepanel.js (activity stream, chat)                    │
│  ├── content.js (indicator injection, inspector)             │
│  └── inspector.js (element picking)                          │
└─────────────────────────────────────────────────────────────┘

browse is the centerpiece: a persistent HTTP server wrapping Playwright-driven Chromium. The CLI (browse/src/cli.ts) is a thin client that sends commands over HTTP to the long-running server (browse/src/server.ts). This architecture means the browser persists across individual command invocations, preserving page state, cookies, and sessions.

design is a standalone tool that calls the OpenAI GPT-4o Responses API for image generation, with iterative refinement, vision-based quality gates, and gallery management.

make-pdf orchestrates Markdown-to-PDF conversion by rendering HTML through the browse server's Chromium instance, using print-optimized CSS.

Skills are template-driven slash commands. Each skill is a .md.tmpl file with resolver placeholders (e.g., {{BROWSE_COMMAND_REFERENCE}}) that get expanded at generation time by TypeScript resolvers. The gen-skill-docs.ts script produces host-specific versions for each supported AI coding environment.

1.2 Process Model

The browse server uses Bun's HTTP server with a single-threaded event loop. Key architectural decisions:

  • Persistent server: The browse server starts once and stays alive, with an idle timeout (BROWSE_IDLE_TIMEOUT). CLI commands talk to it over localhost HTTP.
  • Token-based auth: The server generates a random token on startup, writes it to a state file, and all /command requests require Bearer <token>.
  • Tab sessions: Each browser tab is managed by a TabSession instance (browse/src/tab-session.ts) that tracks refs, frames, and loaded HTML independently.
  • Watchdog: The CLI can set BROWSE_PARENT_PID so the server auto-exits when the parent process dies (set to 0 to disable).

1.3 Technology Stack

Technology Version Purpose
Bun >=1.0.0 Runtime, package manager, test runner, compiler
TypeScript — Primary language across all components
Playwright ^1.58.2 Browser automation (Chromium)
puppeteer-core ^24.40.0 Additional browser CDP APIs
@huggingface/transformers ^4.1.0 ML model loading for security classifier
@ngrok/ngrok ^1.7.0 Tunneling for remote browser access
marked ^18.0.2 Markdown parsing (make-pdf)
diff ^7.0.0 Text diffing
OpenAI GPT-4o — Design image generation + vision quality gate
@anthropic-ai/claude-agent-sdk 0.2.117 Agent SDK for sidebar agent (dev dependency)
@anthropic-ai/sdk ^0.78.0 Anthropic API (dev dependency)
Supabase Deno edge functions Backend telemetry + community stats
Chrome Extension Manifest V3 — Browser integration side panel

1.4 Module Reference

browse/src/ — Core Browser Engine

Module Responsibility
server.ts Persistent HTTP server — routes, lifecycle, port discovery
cli.ts Thin CLI client — argument parsing, server auto-start
browser-manager.ts BrowserManager class — Chromium lifecycle, tab management, viewport, context
tab-session.ts TabSession class — per-tab refs, frames, loaded HTML state
read-commands.ts Read-only commands: js, eval, css, attrs, console, network, source, text, refs
write-commands.ts Mutating commands: click, fill, select, goto, load-html, upload, scroll, hover, wait
meta-commands.ts Utility commands: pdf, screenshot, tabs, state, frame, mhtml
snapshot.ts Accessibility tree extraction + annotated screenshots
security-classifier.ts ML ensemble for prompt injection detection
content-security.ts Content filtering — marks output between BEGIN/END UNTRUSTED markers
url-validation.ts URL allowlist/blocklist, cloud metadata blocking, file:// handling
path-security.ts File path validation — enforces safe directory allowlist
activity.ts SSE real-time activity feed for Chrome extension
audit.ts Append-only JSONL audit trail at .gstack/browse-audit.jsonl
network-capture.ts SizeCappedBuffer for network request/response logging
buffers.ts CircularBuffer for console, network, and dialog capture
token-registry.ts Multi-agent token management with read/write/admin/meta/control scopes
tunnel-denial-log.ts Logs denied tunnel access attempts
sse-session-cookie.ts Session tracking for SSE connections
sidebar-agent.ts Claude agent powering the Chrome sidebar chat
cookie-import-browser.ts Import cookies from installed browsers (Chrome, Firefox, etc.)
cookie-picker-routes.ts / cookie-picker-ui.ts Cookie selection UI and HTTP routes
config.ts resolveConfig() — state dir, project detection
platform.ts OS detection, temp directories
error-handling.ts safeUnlink, safeKill, isProcessAlive utilities
find-browse.ts Binary discovery for external callers
media-extract.ts Media URL extraction from pages
welcome.html Default page served in new tabs

design/src/ — AI Design Tool

Module Responsibility
cli.ts Entry point, subcommand routing
auth.ts OpenAI API key resolution (env, config file)
generate.ts Image generation via OpenAI Responses API
iterate.ts Iterative design refinement with feedback loop
evolve.ts Design evolution using vision feedback
check.ts Vision-based quality gate (GPT-4o evaluates output)
compare.ts Side-by-side design comparison
gallery.ts Design gallery management
serve.ts Local gallery HTTP server
brief.ts Structured design brief interface
session.ts Design session persistence
memory.ts Design memory/preferences
variants.ts A/B variant generation
diff.ts Visual diff between designs
design-to-code.ts Convert mockups to implementation code

make-pdf/src/ — PDF Rendering Pipeline

Module Responsibility
cli.ts Entry point, argument parsing
orchestrator.ts ProgressReporter class — multi-file PDF orchestration
render.ts Markdown to HTML to PDF rendering chain
browseClient.ts Typed shell-out wrapper for browse CLI
pdftotext.ts PDF text extraction for verification
smartypants.ts Typography improvement (curly quotes, dashes)
print-css.ts Print-optimized CSS injection
setup.ts One-time setup routine
types.ts BrowseClientError and shared types

lib/ — Shared Libraries

Module Responsibility
worktree.ts WorktreeManager class — Git worktree management for isolated testing

scripts/ — Build & Generation

Module Responsibility
gen-skill-docs.ts Multi-host skill documentation generation
resolvers/index.ts Template resolver registry
resolvers/browse.ts Command reference, snapshot flags, setup instructions
resolvers/composition.ts INVOKE_SKILL cross-skill composition
resolvers/confidence.ts Finding confidence calibration
resolvers/constants.ts AI slop blacklist, design constants
resolvers/design.ts Design review integration
resolvers/codex-helpers.ts Codex frontmatter transformation
resolvers/model-overlay.ts Model-specific behavior overlays
resolvers/review.ts Code review resolver
resolvers/review-army.ts Multi-agent review orchestration
resolvers/testing.ts Test strategy resolver
resolvers/gbrain.ts GBrain integration resolver
resolvers/learnings.ts Cross-session learning resolver
resolvers/make-pdf.ts PDF generation resolver
resolvers/preamble.ts Skill preamble generation
resolvers/question-tuning.ts Question quality tuning
resolvers/dx.ts Developer experience resolver
resolvers/utility.ts Utility helpers
host-adapters/openclaw-adapter.ts OpenClaw-specific adapter

2. System Requirements

2.1 Runtime Requirements

Requirement Minimum Recommended
Bun >=1.0.0 Latest stable
OS macOS, Linux, Windows (WSL or native) macOS or Linux
RAM 2 GB free 4+ GB (Chromium is memory-hungry)
Disk 500 MB (Chromium + dependencies) 1+ GB with cache
Network Required for design tool, telemetry, tunneling Broadband for headed browser use

2.2 External Service Dependencies

Service Required For Authentication
OpenAI API design subcommands OPENAI_API_KEY env var
Anthropic API Sidebar agent (dev) ANTHROPIC_API_KEY env var
ngrok Remote tunnel access NGROK_AUTHTOKEN env var
Supabase Telemetry, community pulse, update checks Public anon key (in supabase/config.sh)

Note

The browse server itself requires no external API keys. It runs entirely locally with Playwright-managed Chromium. API keys are only needed for the design tool (OpenAI) and optional features like tunneling (ngrok) or sidebar chat (Anthropic).

2.3 Supported AI Coding Hosts

gstack generates host-specific skill files for these environments:

Host Config File Notes
Claude Code hosts/claude.ts Primary target
OpenAI Codex CLI hosts/codex.ts Codex frontmatter transformation
Cursor hosts/cursor.ts —
Factory Droid hosts/factory.ts —
Kiro hosts/kiro.ts —
OpenCode hosts/opencode.ts —
Slate hosts/slate.ts —
OpenClaw hosts/openclaw.ts Custom adapter in scripts/host-adapters/
Hermes hosts/hermes.ts —
GBrain hosts/gbrain.ts Dedicated resolver

3. Configuration Reference

gstack is configured entirely through environment variables. There are no YAML or TOML configuration files.

3.1 Browse Server Configuration

Variable Default Description
BROWSE_PORT Auto-discovered Fix the server to a specific port
BROWSE_IDLE_TIMEOUT Server default Idle timeout before auto-shutdown (seconds)
BROWSE_HEADED 0 Set to 1 for headed Chromium (visible browser window)
BROWSE_HEADLESS_SKIP 0 Skip headless browser launch entirely
BROWSE_PARENT_PID Parent PID PID to watch — server exits when this process dies. Set 0 to disable watchdog
BROWSE_NO_AUTOSTART 0 Prevent CLI from auto-starting the server
BROWSE_TAB — Pin CLI operations to a specific tab ID
BROWSE_SERVER_PORT — Server port for sidebar agent communication
BROWSE_STATE_FILE .gstack/browse-state.json Override path for server state file
BROWSE_EXTENSIONS_DIR — Directory containing Chrome extensions to load
GSTACK_CHROMIUM_PATH Playwright default Path to a custom Chromium binary
GSTACK_BROWSE_MAX_HTML_BYTES — Maximum HTML payload size for load-html command
GSTACK_SLUG Auto-detected Project slug identifier
GSTACK_SKILL_ROOT — Custom root directory for skill discovery

Tip

For CI/CD pipelines, BROWSE_PARENT_PID=0 prevents the watchdog from killing the server if the parent shell exits. Combine with BROWSE_PORT for deterministic port assignment in parallel test environments.

3.2 Security Configuration

Variable Default Description
GSTACK_SECURITY_OFF 0 Set to 1 to disable the ML security classifier entirely
GSTACK_SECURITY_ENSEMBLE All layers Configure which ML ensemble layers to activate
GSTACK_HAIKU_TIMEOUT_MS — Timeout in ms for the Haiku classifier layer
BROWSE_CONTENT_FILTER — Content security filter mode for untrusted web content

Warning

Setting GSTACK_SECURITY_OFF=1 disables prompt injection detection entirely. This removes the ML ensemble that protects against malicious web content being injected into AI agent conversations. Only disable for debugging or in fully trusted environments.

3.3 Tunnel Configuration

Variable Default Description
BROWSE_TUNNEL 0 Enable ngrok tunnel for remote access
NGROK_AUTHTOKEN — ngrok authentication token (required for tunneling)
NGROK_DOMAIN — Custom ngrok domain

3.4 Design Tool Configuration

Variable Default Description
OPENAI_API_KEY — OpenAI API key for GPT-4o image generation and vision
HOME System default Home directory (used for API key file resolution)

3.5 PDF Tool Configuration

Variable Default Description
BROWSE_BIN Auto-discovered Override path to the browse binary
PDFTOTEXT_BIN Auto-discovered Override path to the pdftotext binary

3.6 Platform / Environment Detection

Variable Default Description
CI — When set, adds --no-sandbox to Chromium launch args
CONTAINER — When set, adds --no-sandbox to Chromium launch args
PROGRAMFILES System default Windows Program Files path (cookie import)
USERPROFILE System default Windows user profile path

3.7 Sidebar Agent Configuration

Variable Default Description
SIDEBAR_QUEUE_PATH — File path for sidebar agent message queue
SIDEBAR_AGENT_TIMEOUT — Timeout for sidebar agent operations
BROWSE_SERVER_PORT — Port the sidebar agent uses to connect to the browse server

3.8 Testing & Eval Configuration

Variable Default Description
EVALS — Enable eval test mode
EVALS_ALL — Run all eval tiers
EVALS_BASE — Base branch for eval comparison
EVALS_TIER — Eval tier selection (gate or periodic)
EVALS_MODEL — Model override for eval runs
ANTHROPIC_API_KEY — Anthropic API key for eval judge
GSTACK_SDK_MAX_CONCURRENCY — Maximum concurrent SDK sessions in test harness

Note

The eval system supports tiered execution: gate evals run on every PR, while periodic evals run on a schedule. Set EVALS_ALL=1 to force all tiers in a single run.


4. Deployment & Scaling

4.1 Installation

# Clone the repository
git clone https://github.com/garrytan/gstack.git
cd gstack

# Install dependencies (Bun handles everything)
bun install

# Build the browse server bundle (required for Windows)
bun run build

4.2 Browse Server Lifecycle

The browse server follows a specific lifecycle:

  1. Auto-start: When the CLI sends a command and no server is running, it auto-starts one (unless BROWSE_NO_AUTOSTART is set).
  2. Port discovery: The server tries a range of ports, or uses BROWSE_PORT if set. If the port is taken, it fails with a clear error.
  3. State file: On startup, the server writes its PID, port, and auth token to the state file (default: .gstack/browse-state.json).
  4. Idle timeout: After BROWSE_IDLE_TIMEOUT seconds of no requests, the server shuts down.
  5. Watchdog: If BROWSE_PARENT_PID is set and that process dies, the server exits.
# Start server explicitly with headed Chromium
BROWSE_HEADED=1 BROWSE_PORT=9222 bun run browse/src/server.ts

# Start with tunneling enabled
BROWSE_TUNNEL=1 NGROK_AUTHTOKEN=your_token bun run browse/src/server.ts

4.3 CI/CD Integration

For CI environments:

# Recommended CI environment variables
export CI=1                    # Adds --no-sandbox for containerized Chromium
export BROWSE_PARENT_PID=0     # Disable watchdog
export BROWSE_PORT=9222        # Fixed port for predictability
export GSTACK_SECURITY_OFF=1   # Optional: skip ML classifier in trusted CI

Important

Chromium requires --no-sandbox inside Docker containers and most CI runners. gstack automatically adds this flag when CI=1 or CONTAINER=1 is set. Without it, the browser will fail to launch with a sandbox-related error.

4.4 Container Deployment

The browse server can run in Docker. Key considerations:

  • Mount a volume for .gstack/ to persist state across restarts
  • Expose the browse server port
  • Set CONTAINER=1 for automatic --no-sandbox
  • Chromium needs shared memory — use --shm-size=2g or mount /dev/shm
FROM oven/bun:latest

WORKDIR /app
COPY . .
RUN bun install

ENV CONTAINER=1
ENV BROWSE_PORT=9222

EXPOSE 9222

CMD ["bun", "run", "browse/src/server.ts"]
docker run -d \
  --shm-size=2g \
  -p 9222:9222 \
  -e CONTAINER=1 \
  -e BROWSE_PORT=9222 \
  -v gstack-state:/app/.gstack \
  gstack-browse

4.5 Multi-Agent Deployment

gstack supports multiple AI agents sharing a single browse server through the token registry:

  1. The primary agent starts the server and gets the admin token from the state file.
  2. Additional agents connect via the /pair endpoint to get scoped tokens.
  3. Token scopes (read, write, admin, meta, control) restrict what each agent can do.

This enables architectures where a supervisor agent delegates browsing tasks to worker agents, each with least-privilege access.

4.6 Remote Access via ngrok

For accessing the browse server from remote machines:

export BROWSE_TUNNEL=1
export NGROK_AUTHTOKEN=your_ngrok_token
export NGROK_DOMAIN=custom.ngrok.io  # Optional: custom domain

# Server will log the tunnel URL on startup
bun run browse/src/server.ts

Caution

The ngrok tunnel exposes your browse server to the internet. While token-based authentication protects the /command endpoint, ensure your ngrok account has appropriate access controls. Denied tunnel access attempts are logged by tunnel-denial-log.ts.


5. Operations

5.1 HTTP API Endpoints

The browse server exposes these HTTP endpoints:

Method Path Auth Purpose
POST /command Bearer token Execute a browse command
GET /health None Server health check
POST /connect None Initial connection handshake
POST /pair Bearer token Register a new agent with scoped token
GET /refs Bearer token Get current page element references
GET /activity/stream Bearer token SSE real-time activity feed
GET /activity/history Bearer token Activity history
GET /sidebar-tabs Bearer token Sidebar tab listing
POST /tunnel/start Bearer token Start ngrok tunnel
GET /file Bearer token Serve local files
POST /batch Bearer token Execute multiple commands in sequence

5.2 Server State File

The browse server persists its state to .gstack/browse-state.json (or the path in BROWSE_STATE_FILE). This file contains:

  • Server PID
  • Server port
  • Authentication token
  • Server start timestamp

The CLI reads this file to discover and authenticate with a running server. If the state file is stale (PID no longer alive), the CLI starts a new server.

5.3 Audit Log

Every command execution is logged to .gstack/browse-audit.jsonl as append-only JSONL. Each entry includes:

  • Timestamp
  • Command name and arguments
  • Agent token (anonymized)
  • Result status
  • Execution duration

This provides a forensic trail for debugging multi-agent interactions and security incidents.

5.4 Telemetry

gstack sends anonymous telemetry to Supabase edge functions:

  • telemetry-ingest: Batch insertion of usage events (max 100 events, max 50KB per request)
  • community-pulse: Aggregated community statistics (cached for 1 hour)
  • update-check: Version ping that logs installation info

Supabase configuration (public, non-secret) lives in supabase/config.sh.

Note

Telemetry is anonymous. Session tracking is gated by telemetry configuration (see issue #1150 for the gating fix).

5.5 Upgrade System

gstack includes a versioned migration system in gstack-upgrade/migrations/:

Version Migration What It Does
v0.15.2.0 Fix skill directory structure Runs gstack-relink for unprefixed skill discovery
v0.16.2.0 Merge resource logs Migrates per-project resources-shown.jsonl to unified builder-profile.jsonl
v1.0.0.0 V1 writing style Prompts for ELI10 vs terse writing style preference
v1.1.3.0 Remove /checkpoint Uninstalls stale /checkpoint skill, replaces with /context-save + /context-restore

Migrations run automatically during gstack updates and are idempotent.

5.6 Monitoring

Health check:

curl http://localhost:9222/health

Process monitoring:

# Check if server is alive using state file
cat .gstack/browse-state.json | jq '.pid' | xargs kill -0

Audit log tail:

tail -f .gstack/browse-audit.jsonl | jq .

6. Performance

6.1 Browser Resource Management

The BrowserManager manages Chromium's resource consumption:

  • Tab limit: Each tab is a TabSession with its own page context. More tabs means more memory.
  • Circular buffers: Console and network captures use CircularBuffer (fixed-size ring buffers) to prevent unbounded memory growth.
  • Size-capped network capture: SizeCappedBuffer in network-capture.ts caps total captured network data.
  • Idle timeout: The server auto-shuts down after inactivity, freeing all Chromium resources.

6.2 Chromium Launch Optimization

The server applies platform-specific Chromium flags:

  • --no-sandbox in CI/container environments
  • Anti-detection patches in headed mode (navigator.webdriver, plugins, languages, CDP artifacts, Permissions API)
  • Custom Chromium binary via GSTACK_CHROMIUM_PATH for pre-warmed or optimized builds

6.3 PDF Rendering Performance

The make-pdf pipeline chains Markdown parsing (marked) through HTML rendering to Chromium's PDF output. For large documents:

  • The ProgressReporter class in orchestrator.ts provides real-time feedback during multi-file orchestration
  • Print-optimized CSS (print-css.ts) ensures clean page breaks and typography
  • smartypants.ts applies typography improvements (curly quotes, em-dashes) in a single pass

6.4 Security Classifier Overhead

The ML security ensemble adds latency to command processing. If this is a bottleneck in trusted environments:

  • Set GSTACK_SECURITY_OFF=1 to disable entirely
  • Configure GSTACK_SECURITY_ENSEMBLE to activate only specific layers
  • Adjust GSTACK_HAIKU_TIMEOUT_MS to cap the Haiku classifier timeout

Tip

In development, the security classifier can add noticeable latency to the first request while ML models load. Subsequent requests use cached models. Pre-warm the server by sending a no-op command after startup.


7. Security

7.1 Authentication Model

The browse server uses a token-based authentication system:

  1. Server token: Generated randomly on each server startup and written to the state file. Required as Bearer <token> header on all /command requests.
  2. Multi-agent tokens: The TokenRegistry (browse/src/token-registry.ts) manages scoped tokens for paired agents.

Token scopes:

Scope Permissions
read Read-only commands (js, eval, css, attrs, text, refs, source, console, network)
write Mutating commands (click, fill, select, goto, load-html, upload, scroll, hover, wait)
admin Server management commands
meta Utility commands (pdf, screenshot, tabs, state, frame)
control Tunnel and extension management

7.2 ML Security Classifier

The security classifier (browse/src/security-classifier.ts) uses an ensemble of five detection layers to identify prompt injection attacks in web content:

Layer Method
testsavant_content ML content classification
transcript_classifier Transcript-based classification
aria_regex Regular expression matching on ARIA/accessibility text
canary Canary token detection
deberta_content DeBERTa-based content classification

The classifier produces verdicts: SAFE, WARN, or BLOCK. Attack telemetry (domain, payload hash, confidence, layer, verdict) is stored in Supabase via migration 004.

Important

Issue #1156 notes that WARN verdicts currently take no defensive action beyond logging. Until this is addressed, WARN-level detections are informational only. Monitor audit logs for WARN verdicts in production deployments.

7.3 Content Security

The content security module (browse/src/content-security.ts) filters untrusted web content before it reaches AI agents:

  • All web-sourced content is wrapped between BEGIN UNTRUSTED CONTENT and END UNTRUSTED CONTENT markers
  • The BROWSE_CONTENT_FILTER environment variable controls filtering aggressiveness
  • This prevents web content from being interpreted as instructions by downstream AI agents

7.4 URL Validation

browse/src/url-validation.ts implements:

  • Cloud metadata blocking: Blocks access to 169.254.169.254 and similar cloud metadata endpoints (SSRF prevention)
  • file:// validation: Restricts file URL access to safe directories
  • Allowlist/blocklist: Configurable URL filtering

7.5 Path Security

browse/src/path-security.ts enforces a safe directory allowlist for all file operations. Any path outside the allowed directories triggers the error:

Path must be within: <SAFE_DIRECTORIES>

7.6 Privacy Filtering

The activity stream (browse/src/activity.ts) automatically redacts:

  • Passwords
  • Authentication tokens
  • Sensitive query parameters

This ensures the Chrome extension's side panel and activity stream do not leak credentials.

BrowserManager tracks imported cookie domains to maintain an elevated security context for those origins. Cookie import (browse/src/cookie-import-browser.ts) supports extracting cookies from installed browsers.

7.8 Anti-Bot Stealth

In headed mode (BROWSE_HEADED=1), gstack patches Chromium to evade bot detection:

  • navigator.webdriver returns false
  • Plugin and language arrays are populated with realistic values
  • CDP (Chrome DevTools Protocol) artifacts are hidden
  • Permissions API behavior is normalized

7.9 Supabase Row-Level Security

The database migrations progressively tighten RLS policies:

  • Reads blocked on all tables (telemetry data is write-only from clients)
  • Updates restricted to tracking columns only (cannot modify event payload)
  • Inserts kept for backward compatibility with older client versions

Verify RLS policies are correctly applied:

./supabase/verify-rls.sh

7.10 Audit Trail

The audit log (browse/src/audit.ts) writes append-only JSONL to .gstack/browse-audit.jsonl. This log is the forensic record for:

  • All command executions
  • Authentication events
  • Security classifier verdicts
  • Tunnel access attempts (denied attempts logged separately by tunnel-denial-log.ts)

Warning

The audit log grows without bound. Implement log rotation for long-running deployments. The log file path is determined by the state directory (.gstack/ by default).


8. Developer Internals

8.1 Repository Structure

gstack/
├── browse/
│   ├── src/              # Browser automation engine
│   │   ├── server.ts     # HTTP server entry point
│   │   ├── cli.ts        # CLI client entry point
│   │   └── ...           # 25+ modules (see Module Reference)
│   └── test/             # Browse tests
├── design/
│   └── src/              # AI design tool (15 modules)
├── make-pdf/
│   └── src/              # PDF pipeline (8 modules)
├── skills/               # SKILL.md.tmpl templates
├── scripts/
│   ├── resolvers/        # Template resolvers (18 resolvers)
│   ├── host-adapters/    # Host-specific adapters
│   └── gen-skill-docs.ts # Multi-host doc generator
├── hosts/                # Per-host config (10 hosts)
├── lib/                  # Shared libraries (worktree.ts)
├── model-overlays/       # Model-specific behavior files
│   ├── claude.md
│   ├── gemini.md
│   ├── gpt.md
│   ├── gpt-5.4.md
│   ├── o-series.md
│   └── opus-4-7.md
├── extension/            # Chrome extension (Manifest V3)
├── supabase/
│   ├── functions/        # Edge functions (3)
│   ├── migrations/       # Schema migrations (001-004)
│   ├── config.sh         # Public Supabase config
│   └── verify-rls.sh     # RLS smoke test
├── gstack-upgrade/
│   └── migrations/       # Version migrations (4)
└── test/
    └── helpers/          # Test utilities

8.2 Key Classes

Class Location Purpose
BrowserManager browse/src/browser-manager.ts Singleton managing Chromium lifecycle, tab creation/destruction, viewport, browser context
TabSession browse/src/tab-session.ts Per-tab state container — element refs, frame navigation, loaded HTML tracking
CircularBuffer browse/src/buffers.ts Fixed-size ring buffer for console and dialog capture
SizeCappedBuffer browse/src/network-capture.ts Size-limited buffer for network request/response logging
WorktreeManager lib/worktree.ts Git worktree creation and cleanup for isolated test environments
ProgressReporter make-pdf/src/orchestrator.ts Progress tracking for multi-file PDF orchestration
CookieImportError browse/src/cookie-import-browser.ts Error type for cookie import failures
BrowseClientError make-pdf/src/types.ts Error type for browse CLI communication failures
PdftotextUnavailableError make-pdf/src/pdftotext.ts Error type when pdftotext binary is not found
RateLimitExhaustedError test/helpers/agent-sdk-runner.ts Error type for exhausted API rate limits in tests
Semaphore test/helpers/agent-sdk-runner.ts Concurrency limiter for parallel SDK test sessions
EvalCollector test/helpers/eval-store.ts Test evaluation result collector

8.3 Skills System Architecture

Skills are the primary interface between gstack and AI coding hosts. The generation pipeline works as follows:

  1. Templates: Each skill has a SKILL.md.tmpl file with resolver placeholders like {{BROWSE_COMMAND_REFERENCE}}, {{INVOKE_SKILL}}, {{CONFIDENCE_CALIBRATION}}.

  2. Resolvers: TypeScript functions in scripts/resolvers/ that generate dynamic content. The resolver registry (scripts/resolvers/index.ts) maps placeholder names to resolver functions.

  3. Host configs: Each host in hosts/ defines path rewrites and frontmatter requirements. For example, Codex requires specific frontmatter transformation (scripts/resolvers/codex-helpers.ts).

  4. Generation: scripts/gen-skill-docs.ts iterates over all templates, runs resolvers, applies host-specific transformations, and writes final .md files.

  5. Model overlays: Files in model-overlays/ provide model-specific behavior adjustments (Claude, Gemini, GPT, GPT-5.4, O-series, Opus 4-7).

8.4 Command System

Browse commands are split into three categories by side-effect profile:

Read commands (browse/src/read-commands.ts) — no page mutation:

Command Description
js / eval Execute JavaScript on the page
css Query computed CSS properties
attrs Get element attributes
console Read console log buffer
network Read network capture buffer
source Get page source HTML
text Extract text content
refs Get element reference map

Write commands (browse/src/write-commands.ts) — mutate page state:

Command Description
goto Navigate to a URL
load-html Load raw HTML into the page
click Click an element
fill Fill a form field
select Select a dropdown option
upload Upload a file
scroll Scroll the page or element
hover Hover over an element
wait Wait for a selector or condition

Meta commands (browse/src/meta-commands.ts) — server/session operations:

Command Description
pdf Generate PDF of current page
screenshot Capture screenshot
tabs List or switch tabs
state Save or load browser state
frame Switch between frames
mhtml Save page as MHTML archive (requires Chromium CDP)

8.5 Snapshot System

The snapshot module (browse/src/snapshot.ts) produces accessibility tree representations and annotated screenshots. These are the primary mechanism by which AI agents "see" web pages:

  • Accessibility tree: Extracts the page's a11y tree into a structured text format that AI agents can reason about
  • Annotated screenshots: Captures the page with element reference overlays for visual grounding

8.6 Testing Strategy

gstack uses Bun's built-in test runner with a tiered evaluation system:

Tier Scope When
Unit tests Individual modules Every change
Gate evals Core functionality (EVALS_TIER=gate) Every PR
Periodic evals Extended coverage (EVALS_TIER=periodic) Scheduled
Full evals Everything (EVALS_ALL=1) Manual

Test infrastructure:

  • test/helpers/agent-sdk-runner.ts: Parallel SDK session runner with Semaphore for concurrency control and RateLimitExhaustedError handling
  • test/helpers/benchmark-judge.ts: LLM-based evaluation judge (uses Anthropic API)
  • test/helpers/e2e-helpers.ts: End-to-end test helpers with eval mode gating
  • test/helpers/eval-store.ts: EvalCollector for aggregating evaluation results
  • test/helpers/session-runner.ts: Session management for eval runs (supports EVALS_MODEL override)
# Run unit tests
bun test

# Run gate evals
EVALS=1 EVALS_TIER=gate bun test

# Run all evals with a specific model
EVALS=1 EVALS_ALL=1 EVALS_MODEL=claude-3-5-sonnet bun test

8.7 Git Worktree Manager

lib/worktree.ts provides the WorktreeManager class for creating isolated Git worktrees. This is used by skills that need to run tests or builds in isolation without affecting the main working directory.

8.8 Code Patterns

Error handling: gstack uses safeUnlink, safeKill, and isProcessAlive utilities (browse/src/error-handling.ts) for defensive cleanup. Custom error classes (CookieImportError, BrowseClientError, PdftotextUnavailableError) provide typed error handling.

State management: The browse server treats the filesystem as persistent state. The state file, audit log, and session cookies are all file-based. resolveConfig() in browse/src/config.ts determines the state directory based on project detection.

Buffer management: Two buffer implementations prevent unbounded memory growth:

  • CircularBuffer (fixed item count, ring buffer) for console/dialog logs
  • SizeCappedBuffer (fixed byte size) for network captures

Platform abstraction: browse/src/platform.ts handles OS detection and temp directory resolution, enabling cross-platform behavior in cookie import, path validation, and process management.

8.9 Contributing

Adding a New Browse Command

  1. Determine the command category (read, write, or meta).
  2. Add the handler function to the appropriate module (read-commands.ts, write-commands.ts, or meta-commands.ts).
  3. Register the command in server.ts's command dispatch.
  4. Update the browse resolver (scripts/resolvers/browse.ts) to include it in generated documentation.
  5. Add tests.

Adding a New Skill

  1. Create a SKILL.md.tmpl file in the skills/ directory.
  2. Use resolver placeholders ({{RESOLVER_NAME}}) for dynamic content.
  3. If a new resolver is needed, add it to scripts/resolvers/ and register it in scripts/resolvers/index.ts.
  4. Run bun run scripts/gen-skill-docs.ts to generate host-specific versions.
  5. Test with each target host.

Adding a New Host

  1. Create a host config file in hosts/ (e.g., hosts/newhost.ts).
  2. Define path rewrites and frontmatter requirements.
  3. Register the host in hosts/index.ts.
  4. If the host needs special handling, create an adapter in scripts/host-adapters/.
  5. Run skill generation and verify output.

Adding a New Resolver

  1. Create a resolver module in scripts/resolvers/.
  2. Export a function that returns the resolved content string.
  3. Register the resolver name in scripts/resolvers/index.ts.
  4. Use the placeholder in skill templates: {{YOUR_RESOLVER_NAME}}.

Adding a Supabase Migration

  1. Create a new migration file in supabase/migrations/ following the naming pattern 00N-description.sql.
  2. Apply the migration to your Supabase project.
  3. Update supabase/verify-rls.sh if the migration adds new tables or policies.
  4. Test with the telemetry-ingest and community-pulse edge functions.

9. Integration Points

9.1 Chrome Extension

The Chrome extension (extension/) connects to the browse server for real-time interaction:

File Role
manifest.json Chrome Manifest V3 configuration
background.js Service worker — health polling, command proxy, ref relay
sidepanel.js / sidepanel.html / sidepanel.css Activity stream display, chat interface
content.js / content.css Page-level indicator injection, inspector fallback
inspector.js / inspector.css Full element inspection overlay
popup.html / popup.js Toolbar popup interface

The extension communicates with the browse server via:

  • /health for connection status polling
  • /activity/stream (SSE) for real-time event streaming
  • /command for executing browse commands from the side panel
  • /refs for element reference data

9.2 Supabase Backend

Tables:

Table Purpose
telemetry_events Raw usage events (write-only from clients)
installations Installation tracking
update_checks Version check history
community_pulse_cache Cached aggregation for community stats

Views:

View Purpose
crash_clusters Aggregated crash data for pattern analysis
skill_sequences Skill usage sequences for workflow detection

Edge functions:

Function Method Limits
telemetry-ingest POST Max 100 events, max 50KB per request
community-pulse GET Cached for 1 hour
update-check GET Logs installation info

Tip

The community-pulse endpoint caches results for one hour. During development, you may need to wait for cache expiration or clear the community_pulse_cache table directly to see updated aggregations.

9.3 Model Overlays

Model overlay files in model-overlays/ provide behavioral adjustments for different LLMs:

Overlay Target Model
claude.md Claude (default)
gemini.md Google Gemini
gpt.md GPT-4 / GPT-4o
gpt-5.4.md GPT-5.4
o-series.md OpenAI O-series (reasoning models)
opus-4-7.md Claude Opus 4-7

These overlays are injected into skill templates via the model-overlay resolver (scripts/resolvers/model-overlay.ts) to tune prompt behavior for each model's strengths and characteristics.

9.4 make-pdf Integration

The make-pdf tool depends on the browse server for rendering:

Markdown → marked parser → HTML + print-css → browse load-html → Chromium PDF

make-pdf/src/browseClient.ts provides a typed wrapper around shell-outs to the browse CLI. Set BROWSE_BIN to override binary discovery. The pipeline includes:

  1. Setup (setup.ts): One-time dependency check
  2. Rendering (render.ts): Markdown to HTML conversion with typography improvements
  3. Orchestration (orchestrator.ts): Multi-file coordination with progress reporting
  4. Verification (pdftotext.ts): Optional text extraction to verify PDF content

10. Troubleshooting

Error: Server failed to start within Ns

Cause: The browse server did not become ready within the startup timeout, typically because Chromium failed to launch.

Solution:

  1. Check that Chromium is installed: bunx playwright install chromium
  2. In containers, ensure CI=1 or CONTAINER=1 is set for --no-sandbox
  3. Verify sufficient shared memory: df -h /dev/shm (need 256MB+)
  4. Check for port conflicts: lsof -i :9222

Prevention: Set BROWSE_PORT to avoid port scanning delays. Use GSTACK_CHROMIUM_PATH for a known-good binary.


Error: Cannot find server.ts. Set BROWSE_SERVER_SCRIPT env or run from the browse source tree.

Cause: The CLI cannot locate the server entry point. This happens when running the browse CLI from outside the gstack directory.

Solution:

  1. Run from within the gstack repository
  2. Or set the BROWSE_SERVER_SCRIPT environment variable to the absolute path of browse/src/server.ts

Prevention: Install gstack globally or use a shell alias that includes the correct working directory.


Error: server-node.mjs not found. Run 'bun run build' to generate the Windows server bundle.

Cause: On Windows, the browse server requires a pre-built bundle that has not been generated.

Solution:

bun run build

Prevention: Always run bun run build after cloning or updating the repository on Windows.


Error: Authentication failed (HTTP 401)

Cause: The CLI is using a stale token that does not match the running server's token.

Solution:

  1. Check the state file: cat .gstack/browse-state.json
  2. Verify the server PID is still alive
  3. If the server was restarted, the CLI will auto-discover the new token on the next command
  4. Delete the state file and let the CLI start a fresh server

Prevention: Let the CLI manage server lifecycle automatically rather than starting the server manually.


Error: [browse] Server crashed twice in a row — aborting

Cause: The server process crashed on two consecutive startup attempts.

Solution:

  1. Check system logs for Chromium crash details
  2. Verify system resources (RAM, disk space)
  3. Try with BROWSE_HEADED=1 to see if the browser window shows an error
  4. Check for conflicting Chromium processes: ps aux | grep chromium

Prevention: Monitor system resources. In CI, allocate sufficient --shm-size for Docker.


Error: Browser not launched

Cause: A command was sent before the browser context was initialized.

Solution:

  1. Wait for the server to fully start (check /health endpoint)
  2. If using BROWSE_HEADLESS_SKIP=1, the browser will not launch — unset this variable

Prevention: Use the CLI's auto-start mechanism rather than manual server management.


Error: Tab N not found

Cause: The specified tab ID does not exist or has been closed.

Solution:

  1. List available tabs: browse tabs
  2. Use a valid tab ID or omit BROWSE_TAB to use the active tab

Prevention: Do not hardcode tab IDs across sessions. Query available tabs before switching.


Error: No active page. Use browse goto <url> first.

Cause: The current tab has no page loaded (e.g., fresh server with no navigation).

Solution:

browse goto https://example.com

Prevention: Always navigate to a URL before running page commands.


Error: [browse] Port N (from BROWSE_PORT env) is in use

Cause: The port specified in BROWSE_PORT is already occupied by another process.

Solution:

  1. Find what is using the port: lsof -i :N (or netstat -tlnp | grep N)
  2. Kill the process or choose a different port
  3. Unset BROWSE_PORT to use automatic port discovery

Prevention: Use port ranges rather than fixed ports in multi-instance deployments.


Error: [browse] No available port after N attempts in range MIN-MAX

Cause: All ports in the auto-discovery range are occupied.

Solution:

  1. Check for zombie browse server processes: ps aux | grep server.ts
  2. Clean up stale state files: rm .gstack/browse-state.json
  3. Kill orphaned Chromium processes

Prevention: Ensure the watchdog (BROWSE_PARENT_PID) is active so servers auto-exit with their parent.


Error: MHTML archive requires Chromium CDP

Cause: The mhtml command was invoked but CDP (Chrome DevTools Protocol) is not available.

Solution: MHTML archiving requires a Chromium-based browser. Ensure you are not using a non-Chromium browser override via GSTACK_CHROMIUM_PATH.

Prevention: Only use mhtml with the default Playwright Chromium or a compatible Chromium binary.


Error: Path must be within: <SAFE_DIRECTORIES>

Cause: A file operation (upload, file serving) attempted to access a path outside the allowed directories.

Solution:

  1. Move the file to a directory within the allowlist
  2. Check browse/src/path-security.ts for the current safe directory list

Prevention: Keep working files within the project directory or configured safe directories.


Error: URL validation failures (cloud metadata, blocked domains)

Cause: The URL validation module blocked a request to a restricted URL.

Solution:

  1. For cloud metadata blocking (169.254.169.254): this is intentional SSRF prevention — do not bypass
  2. For file:// URLs: ensure the file path is within safe directories
  3. Check URL against the allowlist/blocklist in browse/src/url-validation.ts

Prevention: Use goto with HTTPS URLs. For local files, use load-html with file content instead of file:// URLs.


Error: Exit code 128 in conductor template creation

Cause: Git operations failed due to unborn HEAD or missing refs (GitHub issues #1174, #1176).

Solution:

  1. Ensure the repository has at least one commit
  2. Check that the current branch has a valid HEAD reference
  3. If using worktrees, verify the main repository is in a clean state

Prevention: Initialize repositories with an initial commit before running conductor skills.


Error: DESIGN_NOT_AVAILABLE in Codex workflows

Cause: Design tool is not available in the Codex environment (GitHub issue #1159).

Solution: The design tool requires OpenAI API access. Verify OPENAI_API_KEY is set and accessible in the Codex environment.

Prevention: Check host compatibility before invoking design workflows. Not all hosts support all gstack features.


Error: Custom OPENAI_BASE_URL not respected

Cause: The design tool does not honor custom OpenAI base URL configuration (GitHub issue #957).

Solution: Currently a known limitation. Use the standard OpenAI API endpoint or monitor issue #957 for a fix.

Prevention: Do not rely on custom base URLs for gstack's design features.


Error: ./setup --help runs install instead of showing help

Cause: The --help flag is not properly intercepted before the install flow (GitHub issue #1133).

Solution: Run gstack --help for general help instead.

Prevention: Refer to this guide for setup options.


Error: ./setup --prefix bug

Cause: The --prefix option in setup has a known issue (GitHub issue #620).

Solution: Use the default installation path or manually configure after setup.

Prevention: Monitor issue #620 for a fix.


Error: Review skill not looking at correct diff

Cause: The review skill examines the wrong diff base (GitHub issue #1152).

Solution: Explicitly specify the base branch when invoking the review skill, or ensure your Git branch tracking is configured correctly.

Prevention: Verify git diff output matches expectations before running the review skill.


Error: Codex generated skills carried Claude defaults

Cause: Host-specific skill generation was not properly transforming Claude defaults to Codex equivalents (GitHub issue #1163).

Solution: Regenerate skills with bun run scripts/gen-skill-docs.ts after updating to a version with this fix.

Prevention: After updating gstack, always regenerate skills for all hosts.


Error: WARN verdict takes no defensive action

Cause: The security classifier's WARN verdict logs the detection but does not block the content (GitHub issue #1156).

Solution: Monitor audit logs for WARN verdicts manually. Consider treating high-confidence WARNs as BLOCKs in your own middleware.

Prevention: Follow issue #1156 for the planned enforcement of WARN verdicts.

Caution

When debugging browse server issues, check the audit log (.gstack/browse-audit.jsonl) first. It contains timestamped records of every command execution, authentication event, and security verdict, making it the fastest path to root cause.


11. Supabase Schema Reference

11.1 Tables

telemetry_events: Stores raw telemetry events. Client-writable (INSERT only), reads blocked by RLS.

installations: Tracks unique gstack installations. Populated by the update-check edge function.

update_checks: Version check history — logs which versions are checking for updates.

community_pulse_cache: Cached aggregation table used by the community-pulse edge function (1-hour TTL).

11.2 Views

View Purpose
crash_clusters Aggregates crash data from telemetry events for pattern analysis
skill_sequences Extracts skill usage sequences from telemetry to identify common workflows

11.3 Migration History

Migration Description
001 Initial schema: telemetry_events, installations
002 Row-level security: block reads, restrict updates, keep inserts
003 Upsert support for telemetry deduplication
004 Attack telemetry columns: domain, payload_hash, confidence, layer, verdict

Note

RLS policies are strict: clients can INSERT telemetry but cannot READ any data back. Telemetry is effectively write-only from the client perspective. All aggregation happens server-side via edge functions.


12. Quick Reference

Environment Variable Cheat Sheet

# Essential browse server config
export BROWSE_PORT=9222
export BROWSE_HEADED=1
export BROWSE_IDLE_TIMEOUT=3600
export BROWSE_PARENT_PID=0

# Security (development only)
export GSTACK_SECURITY_OFF=1

# Tunneling
export BROWSE_TUNNEL=1
export NGROK_AUTHTOKEN=your_token

# Design tool
export OPENAI_API_KEY=sk-your-key

# CI/containers
export CI=1
export CONTAINER=1

# Custom Chromium
export GSTACK_CHROMIUM_PATH=/usr/bin/chromium-browser

Common Operations

# Start headed browse server
BROWSE_HEADED=1 bun run browse/src/server.ts

# Health check
curl http://localhost:9222/health

# Run all tests
bun test

# Run gate evals
EVALS=1 EVALS_TIER=gate bun test

# Generate skill docs for all hosts
bun run scripts/gen-skill-docs.ts

# Build Windows bundle
bun run build

# Verify Supabase RLS
./supabase/verify-rls.sh

# Tail audit log
tail -f .gstack/browse-audit.jsonl | jq .

HTTP API Quick Reference

# Execute a command
curl -X POST http://localhost:9222/command \
  -H "Authorization: Bearer $(jq -r .token .gstack/browse-state.json)" \
  -H "Content-Type: application/json" \
  -d '{"command": "goto", "args": ["https://example.com"]}'

# Pair a new agent with read-only access
curl -X POST http://localhost:9222/pair \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"scopes": ["read"]}'

# Get element references
curl http://localhost:9222/refs \
  -H "Authorization: Bearer $TOKEN"

# Stream activity (SSE)
curl -N http://localhost:9222/activity/stream \
  -H "Authorization: Bearer $TOKEN"

See the User Guide for hands-on usage tutorials, CLI command reference, and workflow examples.