Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 0 additions & 1 deletion .claude/skills/autoplan

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/autoplan/SKILL.md
1 change: 0 additions & 1 deletion .claude/skills/benchmark

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/benchmark-models/SKILL.md
1 change: 1 addition & 0 deletions .claude/skills/benchmark/SKILL.md
1 change: 0 additions & 1 deletion .claude/skills/browse

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/browse/SKILL.md
1 change: 0 additions & 1 deletion .claude/skills/canary

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/canary/SKILL.md
1 change: 0 additions & 1 deletion .claude/skills/careful

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/careful/SKILL.md
1 change: 0 additions & 1 deletion .claude/skills/codex

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/codex/SKILL.md
1 change: 0 additions & 1 deletion .claude/skills/connect-chrome

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/connect-chrome/SKILL.md
1 change: 1 addition & 0 deletions .claude/skills/context-restore/SKILL.md
1 change: 1 addition & 0 deletions .claude/skills/context-save/SKILL.md
1 change: 0 additions & 1 deletion .claude/skills/cso

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/cso/SKILL.md
1 change: 0 additions & 1 deletion .claude/skills/design-consultation

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/design-consultation/SKILL.md
1 change: 0 additions & 1 deletion .claude/skills/design-html

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/design-html/SKILL.md
1 change: 0 additions & 1 deletion .claude/skills/design-review

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/design-review/SKILL.md
1 change: 0 additions & 1 deletion .claude/skills/design-shotgun

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/design-shotgun/SKILL.md
1 change: 1 addition & 0 deletions .claude/skills/devex-review/SKILL.md
1 change: 0 additions & 1 deletion .claude/skills/document-release

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/document-release/SKILL.md
1 change: 0 additions & 1 deletion .claude/skills/freeze

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/freeze/SKILL.md
1 change: 0 additions & 1 deletion .claude/skills/gstack-upgrade

This file was deleted.

1 change: 1 addition & 0 deletions .claude/skills/gstack-upgrade/SKILL.md
79 changes: 66 additions & 13 deletions .claude/skills/gstack/.github/docker/Dockerfile.ci
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,86 @@ FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive

# System deps
RUN apt-get update && apt-get install -y --no-install-recommends \
git curl unzip ca-certificates jq bc gpg \
# Switch apt sources to Hetzner's public mirror.
# Ubicloud runners (Hetzner FSN1-DC21) hit reliable connection timeouts to
# archive.ubuntu.com:80 — observed 90+ second outages on multiple builds.
# Hetzner's mirror is publicly accessible from any cloud and route-local for
# Ubicloud, so this fixes both reliability and latency. Ubuntu 24.04 uses
# the deb822 sources format at /etc/apt/sources.list.d/ubuntu.sources.
#
# Using HTTP (not HTTPS) intentionally: the base ubuntu:24.04 image ships
# without ca-certificates, so HTTPS apt fails with "No system certificates
# available." Apt's security model verifies via GPG-signed Release files,
# not TLS, so HTTP here is no weaker than the upstream defaults.
RUN sed -i \
-e 's|http://archive.ubuntu.com/ubuntu|http://mirror.hetzner.com/ubuntu/packages|g' \
-e 's|http://security.ubuntu.com/ubuntu|http://mirror.hetzner.com/ubuntu/packages|g' \
/etc/apt/sources.list.d/ubuntu.sources

# Also make apt itself resilient — per-package retries + generous timeouts.
# Hetzner's mirror is reliable but individual packages can still blip; the
# retry config means a single failed fetch doesn't nuke the whole build.
RUN printf 'Acquire::Retries "5";\nAcquire::http::Timeout "30";\nAcquire::https::Timeout "30";\n' \
> /etc/apt/apt.conf.d/80-retries

# System deps (retry apt-get update + install as a unit — even Hetzner can blip).
# Includes xz-utils so the Node.js .tar.xz download below can decompress.
RUN for i in 1 2 3; do \
apt-get update && apt-get install -y --no-install-recommends \
git curl unzip xz-utils ca-certificates jq bc gpg && break || \
(echo "apt retry $i/3 after failure"; sleep 10); \
done \
&& rm -rf /var/lib/apt/lists/*

# GitHub CLI
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
RUN curl --retry 5 --retry-delay 5 --retry-connrefused -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| gpg --dearmor -o /usr/share/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
| tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
&& apt-get update && apt-get install -y --no-install-recommends gh \
&& for i in 1 2 3; do \
apt-get update && apt-get install -y --no-install-recommends gh && break || \
(echo "gh install retry $i/3"; sleep 10); \
done \
&& rm -rf /var/lib/apt/lists/*

# Node.js 22 LTS (needed for claude CLI)
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*
# Node.js 22 LTS (needed for claude CLI).
# Install from the official nodejs.org tarball instead of NodeSource's apt setup.
# NodeSource's setup_22.x script runs its own `apt-get update` + `apt-get install gnupg`,
# both of which depend on archive.ubuntu.com / security.ubuntu.com being reachable.
# Ubicloud CI runners frequently can't reach those mirrors (connection timeouts),
# and "gnupg" was renamed to "gpg" on Ubuntu 24.04 anyway, so NodeSource's script
# fails before it can add its own repo. Direct tarball download is network-simpler
# (one host: nodejs.org) and doesn't touch apt at all.
ENV NODE_VERSION=22.20.0
RUN curl --retry 5 --retry-delay 5 --retry-connrefused -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz" -o /tmp/node.tar.xz \
&& tar -xJ -C /usr/local --strip-components=1 --no-same-owner -f /tmp/node.tar.xz \
&& rm -f /tmp/node.tar.xz \
&& node --version \
&& npm --version

# Bun (install to /usr/local so non-root users can access it)
ENV BUN_INSTALL="/usr/local"
RUN curl -fsSL https://bun.sh/install | BUN_VERSION=1.3.10 bash
RUN curl --retry 5 --retry-delay 5 --retry-connrefused -fsSL https://bun.sh/install \
| BUN_VERSION=1.3.10 bash

# Claude CLI
RUN npm i -g @anthropic-ai/claude-code

# Playwright system deps (Chromium) — needed for browse E2E tests
RUN npx playwright install-deps chromium

# Linux has neither Helvetica nor Arial. make-pdf's print CSS stacks fall back
# to Liberation Sans (metric-compatible Arial clone, SIL OFL 1.1) so PDFs don't
# render in DejaVu Sans. playwright install-deps happens to pull this in today,
# but the dep is implicit and could change — install explicitly so upgrades
# can't silently regress rendering.
RUN for i in 1 2 3; do \
apt-get update && apt-get install -y --no-install-recommends fonts-liberation fontconfig && break || \
(echo "fonts-liberation install retry $i/3"; sleep 10); \
done \
&& fc-cache -f \
&& rm -rf /var/lib/apt/lists/*

# Pre-install dependencies (cached layer — only rebuilds when package.json changes)
COPY package.json /workspace/
WORKDIR /workspace
Expand All @@ -44,7 +96,9 @@ RUN npx playwright install chromium \

# Verify everything works
RUN bun --version && node --version && claude --version && jq --version && gh --version \
&& npx playwright --version
&& npx playwright --version \
&& fc-match "Liberation Sans" | grep -qi "Liberation" \
|| (echo "ERROR: fonts-liberation not installed — make-pdf PDFs will render in DejaVu Sans" && exit 1)

# At runtime: checkout overwrites /workspace, but node_modules persists
# if we move it out of the way and symlink back
Expand All @@ -59,5 +113,4 @@ RUN useradd -m -s /bin/bash runner \
&& chmod -R a+rX /opt/node_modules_cache \
&& mkdir -p /home/runner/.gstack && chown -R runner:runner /home/runner/.gstack \
&& chmod 1777 /tmp \
&& mkdir -p /home/runner/.bun && chown -R runner:runner /home/runner/.bun \
&& chmod -R 1777 /tmp
&& mkdir -p /home/runner/.bun && chown -R runner:runner /home/runner/.bun
80 changes: 80 additions & 0 deletions .claude/skills/gstack/.github/workflows/make-pdf-gate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: make-pdf copy-paste gate
on:
pull_request:
branches: [main]
paths:
- 'make-pdf/**'
- 'browse/src/meta-commands.ts'
- 'browse/src/write-commands.ts'
- 'browse/src/commands.ts'
- 'browse/src/cli.ts'
- 'scripts/resolvers/make-pdf.ts'
- 'package.json'
- '.github/workflows/make-pdf-gate.yml'
workflow_dispatch:

concurrency:
group: make-pdf-gate-${{ github.head_ref }}
cancel-in-progress: true

jobs:
gate:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
# Windows is tolerant-mode — Xpdf / Poppler-Windows extraction
# differs enough from the Linux/macOS baseline that the strict
# exact-diff gate is unreliable. Enable once the normalized
# comparator proves tolerant enough (Codex round 2 #18).
#
# include:
# - os: windows-latest
# tolerant: true

runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4

- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Install poppler (macOS)
if: matrix.os == 'macos-latest'
run: brew install poppler

- name: Install poppler-utils (Ubuntu)
if: matrix.os == 'ubuntu-latest'
run: sudo apt-get update && sudo apt-get install -y poppler-utils

- name: Install Playwright Chromium
run: bunx playwright install chromium

- name: Build binaries
run: bun run build

- name: ad-hoc codesign (Apple Silicon)
if: matrix.os == 'macos-latest'
run: |
for bin in browse/dist/browse browse/dist/find-browse design/dist/design make-pdf/dist/pdf; do
codesign --remove-signature "$bin" 2>/dev/null || true
codesign -s - -f "$bin" || true
done

- name: Log toolchain versions
run: |
echo "OS: ${{ matrix.os }}"
bun --version
which pdftotext && pdftotext -v 2>&1 | head -1 || true

- name: Run make-pdf unit tests
run: bun test make-pdf/test/*.test.ts

- name: Run combined-features copy-paste gate (P0)
env:
BROWSE_BIN: ${{ github.workspace }}/browse/dist/browse
run: bun test make-pdf/test/e2e/combined-gate.test.ts
14 changes: 14 additions & 0 deletions .claude/skills/gstack/.gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
.env
node_modules/
dist/
browse/dist/
design/dist/
make-pdf/dist/
bin/gstack-global-discover
.gstack/
.claude/skills/
.claude/scheduled_tasks.lock
.claude/*.lock
.agents/
.factory/
.kiro/
.opencode/
.slate/
.cursor/
.openclaw/
.hermes/
.gbrain/
.context/
extension/.auth.json
.gstack-worktrees/
Expand All @@ -18,3 +29,6 @@ extension/.auth.json
.env.*
!.env.example
supabase/.temp/

# Throughput analysis — local-only, regenerate via scripts/garry-output-comparison.ts
docs/throughput-*.json
25 changes: 24 additions & 1 deletion .claude/skills/gstack/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,26 @@ Cookies are the most sensitive data gstack handles. The design:

The browser registry (Comet, Chrome, Arc, Brave, Edge) is hardcoded. Database paths are constructed from known constants, never from user input. Keychain access uses `Bun.spawn()` with explicit argument arrays, not shell string interpolation.

### Prompt injection defense (sidebar agent)

The Chrome sidebar agent has tools (Bash, Read, Glob, Grep, WebFetch) and reads hostile web pages, so it's the part of gstack most exposed to prompt injection. Defense is layered, not single-point.

1. **L1-L3 content security (`browse/src/content-security.ts`).** Runs on every page-content command and every tool output: datamarking, hidden-element strip, ARIA regex, URL blocklist, and a trust-boundary envelope wrapper. Applied at both the server and the agent.

2. **L4 ML classifier — TestSavantAI (`browse/src/security-classifier.ts`).** A 22MB BERT-small ONNX model (int8 quantized) bundled with the agent. Runs locally, no network. Scans every user message and every Read/Glob/Grep/WebFetch tool output before Claude sees it. Opt-in 721MB DeBERTa-v3 ensemble via `GSTACK_SECURITY_ENSEMBLE=deberta`.

3. **L4b transcript classifier.** A Claude Haiku pass that looks at the full conversation shape (user message, tool calls, tool output), not just text. Gated by `LOG_ONLY: 0.40` so most clean traffic skips the paid call.

4. **L5 canary token (`browse/src/security.ts`).** A random token injected into the system prompt at session start. Rolling-buffer detection across `text_delta` and `input_json_delta` streams catches the token if it shows up anywhere in Claude's output, tool arguments, URLs, or file writes. Deterministic BLOCK — if the token leaks, the attacker convinced Claude to reveal the system prompt, and the session ends.

5. **L6 ensemble combiner (`combineVerdict`).** BLOCK requires agreement from two ML classifiers at >= `WARN` (0.60), not a single confident hit. This is the Stack Overflow instruction-writing false-positive mitigation. On tool-output scans, single-layer high confidence BLOCKs directly — the content wasn't user-authored, so the FP concern doesn't apply.

**Critical constraint:** `security-classifier.ts` runs only in the sidebar-agent process, never in the compiled browse binary. `@huggingface/transformers` v4 requires `onnxruntime-node`, which fails `dlopen` from Bun compile's temp extract directory. Only the pure-string pieces (canary inject/check, verdict combiner, attack log, status) are in `security.ts`, which is safe to import from `server.ts`.

**Env knobs:** `GSTACK_SECURITY_OFF=1` is a real kill switch (skips ML scan, canary still injects). Model cache at `~/.gstack/models/testsavant-small/` (112MB, first run) and `~/.gstack/models/deberta-v3-injection/` (721MB, opt-in only). Attack log at `~/.gstack/security/attempts.jsonl` (salted sha256 + domain, rotates at 10MB, 5 generations). Per-device salt at `~/.gstack/security/device-salt` (0600), cached in-process to survive FS-unwritable environments.

**Visibility.** The sidebar header shows a shield icon (green/amber/red) polled via `/sidebar-chat`. A centered banner appears on canary leak or BLOCK verdict with the exact layer scores. `bin/gstack-security-dashboard` aggregates local attempts; `supabase/functions/community-pulse` aggregates opt-in community telemetry across users.

## The ref system

Refs (`@e1`, `@e2`, `@c1`) are how the agent addresses page elements without writing CSS selectors or XPath.
Expand Down Expand Up @@ -208,6 +228,9 @@ Templates contain the workflows, tips, and examples that require human judgment.
| `{{CODEX_PLAN_REVIEW}}` | `gen-skill-docs.ts` | Optional cross-model plan review (Codex or Claude subagent fallback) for /plan-ceo-review and /plan-eng-review |
| `{{DESIGN_SETUP}}` | `resolvers/design.ts` | Discovery pattern for `$D` design binary, mirrors `{{BROWSE_SETUP}}` |
| `{{DESIGN_SHOTGUN_LOOP}}` | `resolvers/design.ts` | Shared comparison board feedback loop for /design-shotgun, /plan-design-review, /design-consultation |
| `{{UX_PRINCIPLES}}` | `resolvers/design.ts` | User behavioral foundations (scanning, satisficing, goodwill reservoir, trunk test) for /design-html, /design-shotgun, /design-review, /plan-design-review |
| `{{GBRAIN_CONTEXT_LOAD}}` | `resolvers/gbrain.ts` | Brain-first context search with keyword extraction, health awareness, and data-research routing. Injected into 10 brain-aware skills. Suppressed on non-brain hosts. |
| `{{GBRAIN_SAVE_RESULTS}}` | `resolvers/gbrain.ts` | Post-skill brain persistence with entity enrichment, throttle handling, and per-skill save instructions. 8 skill-specific save formats. |

This is structurally sound — if a command exists in code, it appears in docs. If it doesn't exist, it can't appear.

Expand All @@ -217,7 +240,7 @@ Every skill starts with a `{{PREAMBLE}}` block that runs before the skill's own

1. **Update check** — calls `gstack-update-check`, reports if an upgrade is available.
2. **Session tracking** — touches `~/.gstack/sessions/$PPID` and counts active sessions (files modified in the last 2 hours). When 3+ sessions are running, all skills enter "ELI16 mode" — every question re-grounds the user on context because they're juggling windows.
3. **Contributor mode** — reads `gstack_contributor` from config. When true, the agent files casual field reports to `~/.gstack/contributor-logs/` when gstack itself misbehaves.
3. **Operational self-improvement** — at the end of every skill session, the agent reflects on failures (CLI errors, wrong approaches, project quirks) and logs operational learnings to the project's JSONL file for future sessions.
4. **AskUserQuestion format** — universal format: context, question, `RECOMMENDATION: Choose X because ___`, lettered options. Consistent across all skills.
5. **Search Before Building** — before building infrastructure or unfamiliar patterns, search first. Three layers of knowledge: tried-and-true (Layer 1), new-and-popular (Layer 2), first-principles (Layer 3). When first-principles reasoning reveals conventional wisdom is wrong, the agent names the "eureka moment" and logs it. See `ETHOS.md` for the full builder philosophy.

Expand Down
Loading
Loading