3.7 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What is gstack
An AI engineering workflow toolkit that turns Claude Code into specialized skills. The core component is a persistent headless Chromium browser daemon accessed via compiled CLI binary. Additional skills (ship, review, plan, retro) are prompt-only SKILL.md files.
Commands
bun install # install dependencies + Playwright Chromium
bun test # run all integration tests (~3s)
bun test browse/test/commands # command integration tests only
bun test browse/test/snapshot # snapshot tests only
bun test --match "*Navigation*" # run tests matching a pattern
bun run dev <cmd> # run CLI from source (no compile step)
bun run build # compile binary to browse/dist/browse (~58MB)
bun run server # start server directly (for debugging)
Architecture
Client-server split: The browse tool is a thin CLI client (cli.ts) that sends HTTP POST requests to a persistent Bun HTTP server (server.ts). The server manages Chromium via Playwright.
CLI (compiled binary) ──HTTP POST──► Bun server (localhost:9400-9410) ──► Playwright ──► Chromium
- State file at
/tmp/browse-server.jsonstores PID, port, and bearer token (UUID per session) - CLI auto-starts server on first call; server auto-shuts down after 30 min idle
- Chromium crash causes server exit; CLI detects and auto-restarts on next call
Snapshot/ref system: The key abstraction for web interaction. snapshot.ts parses Playwright's accessibility tree (page.locator().ariaSnapshot()), assigns @e1, @e2... refs to elements, and builds a Map<string, Locator>. Commands like click @e3 resolve the ref to a Playwright Locator. Refs are invalidated on navigation.
Command organization: Commands are split by mutation semantics:
read-commands.ts— non-mutating (text, html, links, js, css, forms, console, network, etc.)write-commands.ts— mutating (goto, click, fill, select, scroll, viewport, etc.)meta-commands.ts— server/tab management (status, stop, restart, tabs, screenshot, pdf, chain, diff)
New commands are registered as routes in server.ts.
Buffers (buffers.ts): Ring buffers (50k cap) capture console messages and network requests in memory, flushed to disk every 1s.
Skills
Each skill directory contains a SKILL.md that Claude discovers. Skills other than browse are prompt-only (no code):
ship/— merge → test → review → version bump → commit → push → PRreview/— two-pass pre-landing review checklistbugfix/— test-driven bug fixing: discover → reproduce → fix → verify → improveplan-ceo-review/— founder-mode planning (expansion/hold/reduction scopes)plan-eng-review/— engineering architecture review with diagramsretro/— weekly retrospective from commit history
Adding a new command
- Add handler in
read-commands.ts(non-mutating) orwrite-commands.ts(mutating) - Register route in
server.ts - Add test in
browse/test/commands.test.tswith HTML fixture if needed bun testthenbun run build
Testing
Tests use Bun's native test runner. Integration tests spin up a local HTTP server (browse/test/test-server.ts) serving fixtures from browse/test/fixtures/, then exercise commands against real Playwright browser instances.
Deploying changes to the active skill
The active skill lives at ~/.claude/skills/gstack/. After changes:
cd ~/.claude/skills/gstack && git fetch origin && git reset --hard origin/main && bun run build
Or copy the binary directly: cp browse/dist/browse ~/.claude/skills/gstack/browse/dist/browse