garrytan/gstack
gstack is a Bun/TypeScript monorepo whose primary artifact is a set of generated SKILL.md prompt files installed into AI agent harnesses (Claude Code first, plus Codex, OpenCode, Cursor, Kiro, Factory, Slate, OpenClaw, Hermes, GBrain). Around the skills sit three compiled Bun binaries (browse daemon CLI, make-pdf, design), a ~3.3K-line persistent Chromium daemon (browse/src/server.ts), a Chrome extension sidebar, an iOS-QA daemon with Swift bridge templates, and a supabase telemetry function. The generator (scripts/gen-skill-docs.ts) renders per-host skill docs from .tmpl templates through a RESOLVERS registry; a bash `setup` script builds binaries and links skills per host. Runtime state lives under ~/.gstack (or GSTACK_HOME / CLAUDE_PLUGIN_DATA via bin/gstack-paths) and per-project .gstack/. CI is GitHub Actions: a secretless required free-test lane and a secret-gated paid eval lane.
- The package 'gstack' v1.87.5 publishes two compiled binaries via the `bin` field — `browse` (browse/dist/browse, compiled from browse/src/cli.ts) and `make-pdf` (make-pdf/dist/pdf) — built with `bun build --compile` in the build:gates script.
- The browse engine is a CLI + persistent daemon pair: browse/src/cli.ts is a thin client that reads <project>/.gstack/browse.json (pid/port/token), auto-spawns the server when absent or dead, then POSTs commands to http://127.0.0.1:<port>/command; browse/src/server.ts is a Bun.serve HTTP daemon that dispatches to Playwright-driven Chromium.
- The daemon binds a random port in 10000-49151 via browse/src/port-allocator.ts (deliberately below the macOS ephemeral pool), auto-shuts-down after BROWSE_IDLE_TIMEOUT (default 30 min), and auto-restarts when the binary version in browse/dist/.version differs from the running server's binaryVersion.
- Every skill is a directory at repo root containing SKILL.md.tmpl (plus optional sections/*.md.tmpl carved-out lazy sections) whose committed SKILL.md is generated by scripts/gen-skill-docs.ts; scripts/discover-skills.ts discovers templates by scanning root + one level of subdirs for SKILL.md.tmpl.
- Generation is driven by a RESOLVERS registry (scripts/resolvers/index.ts) mapping ~90 {{PLACEHOLDER}} names to generator functions in domain modules (aside.ts, browse.ts, design.ts, review.ts, testing.ts, gbrain.ts, etc.); each host config can suppress resolvers via suppressedResolvers.
- Host support is declarative: hosts/*.ts configs built by defineHost() in hosts/define-host.ts are registered in hosts/index.ts ALL_HOST_CONFIGS (10 hosts: claude, codex, factory, kiro, opencode, slate, cursor, openclaw, hermes, gbrain); the HostConfig interface + validateHostConfig live in scripts/host-config.ts and are consumed by the generator, setup, and tests with no per-host code.
- `./setup` is a 3262-line bash installer (bash-3.2-clean, umask 077) that requires bun, builds the browse/make-pdf/design binaries, regenerates skill docs per host, and symlinks skills into host dirs like ~/.claude/skills or ${CODEX_HOME:-~/.codex}/skills; on Windows it falls back to cp -R copies via the _link_or_copy helper pinned by a test.
- Runtime state roots are resolved by the sourced helper bin/gstack-paths, which emits shell-quoted GSTACK_STATE_ROOT (GSTACK_HOME → CLAUDE_PLUGIN_DATA → ~/.gstack → .gstack), PLAN_ROOT, and TMP_ROOT so skills work as Claude plugin, global install, or CI checkout.
- The Chrome extension (extension/manifest.json, MV3) pins a fixed extension key whose derived ID is the only Origin allowed to mint the daemon root token via POST /extension-token; it provides the headed GStack Browser's sidepanel (activity feed, @ref overlays, PTY terminal).
- The iOS-QA subsystem pairs a Mac-side daemon (ios-qa/daemon/src: index.ts, devicectl.ts, auth-mint.ts, tailscale-localapi.ts, session-tokens.ts) with Swift bridge templates (ios-qa/templates/*.template) injected into the target app, plus CLIs gstack-ios-qa-daemon/-mint/-regen in bin/.
- CI is GitHub Actions with 17 workflows; the merge gates are free-tests.yml (secretless, REQUIRED) and evals.yml (paid, gate-tier). Supporting lanes include windows-free-tests.yml, evals-periodic.yml (weekly EVALS_ALL), quality-gate.yml (secret scan), osv-scanner.yml, skill-docs.yml (generated-doc freshness), and cso-runtime-* image pipelines.
- External integrations: the Aside browser via `aside repl`/`aside exec` CLI (scripts/resolvers/aside.ts), ngrok tunnels via the @ngrok/ngrok dependency for pair-agent, OpenAI image API in design/, Anthropic/OpenAI/Gemini APIs for paid evals, and an optional Supabase community-pulse function for opt-in telemetry.
- Dependencies are deliberately thin: playwright (patched via patchedDependencies patches/playwright-core@1.62.1.patch), @huggingface/transformers for the sidecar classifier, @ngrok/ngrok, marked, html-to-docx, diff, socks, cross-spawn; dev adds the Claude Agent SDK and xterm for the sidebar terminal.
- Two non-obvious deployment surfaces exist: agents-digest/gstack-AGENTS.md, a committed ~2KB instruction-tier digest generated by scripts/gen-agents-digest.ts for rules-reading hosts, and gstack/llms.txt generated by scripts/gen-llms-txt.ts.