scrape this page, get data from, pull from, extract from, what is on
When to invoke this skill
First call on a new intent prototypes the flow
via $B primitives and returns JSON. Subsequent calls on a matching intent
route to a codified browser-skill and return in ~200ms. Read-only — for
mutating flows (form fills, clicks, submissions), use /automate.
Use when asked to "scrape", "get data from", "pull", "extract from", or
"what's on" a page.
2 files · 38 KB33 KB
Install
It’s free, and every skill you add syncs into every AI tool on your computer, instantly.
_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true)
[ -n "$_UPD" ] && echo"$_UPD" || truemkdir -p ~/.gstack/sessions
touch ~/.gstack/sessions/"$PPID"
_SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ')
find ~/.gstack/sessions -mmin +120 -type f -execrm {} + 2>/dev/null || true
_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo"true")
_PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo"yes" || echo"no")
_BRANCH=$(git branch --show-current 2>/dev/null || echo"unknown")
echo"BRANCH: $_BRANCH"
_SKILL_PREFIX=$(~/.claude/skills/gstack/bin/gstack-config get skill_prefix 2>/dev/null || echo"false")
echo"PROACTIVE: $_PROACTIVE"echo"PROACTIVE_PROMPTED: $_PROACTIVE_PROMPTED"echo"SKILL_PREFIX: $_SKILL_PREFIX"source <(~/.claude/skills/gstack/bin/gstack-repo-mode 2>/dev/null) || true
REPO_MODE=${REPO_MODE:-unknown}echo"REPO_MODE: $REPO_MODE"
_SESSION_KIND=$(~/.claude/skills/gstack/bin/gstack-session-kind 2>/dev/null || echo"interactive")
case"$_SESSION_KIND"in spawned|headless|interactive) ;; *) _SESSION_KIND="interactive" ;; esacecho"SESSION_KIND: $_SESSION_KIND"# Conductor host: AskUserQuestion is unreliable here (native disabled, MCP# variant flaky), so skills render decisions as prose instead of calling the# tool. Gated on !headless so an eval/CI run INSIDE Conductor (GSTACK_HEADLESS)# still BLOCKs rather than rendering prose to nobody.if [ "$_SESSION_KIND" != "headless" ] && { [ -n "${CONDUCTOR_WORKSPACE_PATH:-}" ] || [ -n "${CONDUCTOR_PORT:-}" ]; }; thenecho"CONDUCTOR_SESSION: true"fi
_ACTIVATED=$([ -f ~/.gstack/.activated ] && echo"yes" || echo"no")
_FIRST_LOOP_SHOWN=$([ -f ~/.gstack/.first-loop-tip-shown ] && echo"yes" || echo"no")
echo"ACTIVATED: $_ACTIVATED"echo"FIRST_LOOP_SHOWN: $_FIRST_LOOP_SHOWN"# First-run project detection: run the detector ONLY on the first-ever skill run# (ACTIVATED=no, interactive) so it stays off the hot path for every run after.
_FIRST_TASK=""if [ "$_ACTIVATED" = "no" ] && [ "$_SESSION_KIND" != "headless" ]; then
_FIRST_TASK=$(~/.claude/skills/gstack/bin/gstack-first-task-detect 2>/dev/null || true)
fiecho"FIRST_TASK: $_FIRST_TASK"
_LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo"yes" || echo"no")
echo"LAKE_INTRO: $_LAKE_SEEN"
_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true)
_TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo"yes" || echo"no")
_TEL_START=$(date +%s)
_SESSION_ID="$$-$(date +%s)"echo"TELEMETRY: ${_TEL:-off}"echo"TEL_PROMPTED: $_TEL_PROMPTED"
_EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo"default")
if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fiecho"EXPLAIN_LEVEL: $_EXPLAIN_LEVEL"
_QUESTION_TUNING=$(~/.claude/skills/gstack/bin/gstack-config get question_tuning 2>/dev/null || echo"false")
echo"QUESTION_TUNING: $_QUESTION_TUNING"
_UPDATE_CHECK=$(~/.claude/skills/gstack/bin/gstack-config get update_check 2>/dev/null || echo"true")
echo"UPDATE_CHECK: $_UPDATE_CHECK"mkdir -p ~/.gstack/analytics
if [ "$_TEL" != "off" ]; thenecho'{"skill":"scrape","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(_repo=$(basename"$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null | tr -cd'a-zA-Z0-9._-'); echo"${_repo:-unknown}")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || truefifor _PF in $(find ~/.gstack/analytics -maxdepth 1 -name '.pending-*' 2>/dev/null); doif [ -f "$_PF" ]; thenif [ "$_TEL" != "off" ] && [ -x "$HOME/.claude/skills/gstack/bin/gstack-telemetry-log" ]; then
~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || truefirm -f "$_PF" 2>/dev/null || truefibreakdoneeval"$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" 2>/dev/null || true
_LEARN_FILE="${GSTACK_HOME:-$HOME/.gstack}/projects/${SLUG:-unknown}/learnings.jsonl"if [ -f "$_LEARN_FILE" ]; then
_LEARN_COUNT=$(wc -l < "$_LEARN_FILE" 2>/dev/null | tr -d ' ')
echo"LEARNINGS: $_LEARN_COUNT entries loaded"if [ "$_LEARN_COUNT" -gt 5 ] 2>/dev/null; then
~/.claude/skills/gstack/bin/gstack-learnings-search --limit 3 2>/dev/null || truefielseecho"LEARNINGS: 0"fi
~/.claude/skills/gstack/bin/gstack-timeline-log '{"skill":"scrape","event":"started","branch":"'"$_BRANCH"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null &
_HAS_ROUTING="no"for _RF in CLAUDE.md AGENTS.md; doif [ -f "$_RF" ] && grep -q "## Skill routing""$_RF" 2>/dev/null; then
_HAS_ROUTING="yes"fidone
_ROUTING_DECLINED=$(~/.claude/skills/gstack/bin/gstack-config get routing_declined 2>/dev/null || echo"false")
echo"HAS_ROUTING: $_HAS_ROUTING"echo"ROUTING_DECLINED: $_ROUTING_DECLINED"
_VENDORED="no"if [ -d ".claude/skills/gstack" ] && [ ! -L ".claude/skills/gstack" ]; thenif [ -f ".claude/skills/gstack/VERSION" ] || [ -d ".claude/skills/gstack/.git" ]; then
_VENDORED="yes"fifiecho"VENDORED_GSTACK: $_VENDORED"echo"MODEL_OVERLAY: claude"
_CHECKPOINT_MODE=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_mode 2>/dev/null || echo"explicit")
_CHECKPOINT_PUSH=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_push 2>/dev/null || echo"false")
echo"CHECKPOINT_MODE: $_CHECKPOINT_MODE"echo"CHECKPOINT_PUSH: $_CHECKPOINT_PUSH"# Plan-mode hint for skills like /spec that branch behavior on plan-mode state.# Claude Code exposes plan mode via system reminders; we detect best-effort# from CLAUDE_PLAN_FILE (set by the harness when plan mode is active) and# fall back to "inactive". Codex hosts and Claude execution mode both end up# inactive, which is the safe default (defaults to file+execute pipeline).if [ -n "${CLAUDE_PLAN_FILE:-}${GSTACK_PLAN_MODE_FORCE:-}" ]; thenexport GSTACK_PLAN_MODE="active"elif [ "${GSTACK_PLAN_MODE:-}" = "active" ]; thenexport GSTACK_PLAN_MODE="active"elseexport GSTACK_PLAN_MODE="inactive"fiecho"GSTACK_PLAN_MODE: $GSTACK_PLAN_MODE"
[ -n "$OPENCLAW_SESSION" ] && echo"SPAWNED_SESSION: true" || true
Plan Mode Safe Operations
In plan mode, allowed because they inform the plan: $B, $D, codex exec/codex review, writes to ~/.gstack/, writes to the plan file, and open for generated artifacts.
Skill Invocation During Plan Mode
If the user invokes a skill in plan mode, the skill takes precedence over generic plan mode behavior. Treat the skill file as executable instructions, not reference. Follow it step by step starting from Step 0; any AskUserQuestion the skill fires is the workflow operating within plan mode, not a violation of it — and a skill whose instructions resolve a question themselves (e.g. a plan-mode auto-select) may legitimately not ask it. AskUserQuestion (any variant — mcp__*__AskUserQuestion or native; see "AskUserQuestion Format → Tool resolution") satisfies plan mode's end-of-turn requirement. If AskUserQuestion is unavailable or a call fails, follow the AskUserQuestion Format failure fallback: headless → BLOCKED; interactive → the prose fallback (also satisfies end-of-turn). At a STOP point, stop immediately. Do not continue the workflow or call ExitPlanMode there. Commands marked "PLAN MODE EXCEPTION — ALWAYS RUN" execute. Call ExitPlanMode only after the skill workflow completes, or if the user tells you to cancel the skill or leave plan mode.
If PROACTIVE is "false", do not auto-invoke or proactively suggest skills. If a skill seems useful, ask: "I think /skillname might help here — want me to run it?"
If SKILL_PREFIX is "true", suggest/invoke /gstack-* names. Disk paths stay ~/.claude/skills/gstack/[skill-name]/SKILL.md.
If UPDATE_CHECK is "false", skip the next two lines — the update-check binary emits nothing in that mode, so there is no UPGRADE_AVAILABLE / JUST_UPGRADED output to act on.
If output shows UPGRADE_AVAILABLE <old> <new>: read ~/.claude/skills/gstack/gstack-upgrade/SKILL.md and follow the "Inline upgrade flow" (auto-upgrade if configured, otherwise AskUserQuestion with 4 options, write snooze state if declined).
If output shows JUST_UPGRADED <from> <to>: print "Running gstack v{to} (just updated!)". If SPAWNED_SESSION is true, skip feature discovery.
Feature discovery, max one prompt per session:
Missing ~/.claude/skills/gstack/.feature-prompted-continuous-checkpoint: AskUserQuestion for Continuous checkpoint auto-commits. If accepted, run ~/.claude/skills/gstack/bin/gstack-config set checkpoint_mode continuous. Always touch marker.
Missing ~/.claude/skills/gstack/.feature-prompted-model-overlay: inform "Model overlays are active. MODEL_OVERLAY shows the patch." Always touch marker.
After upgrade prompts, continue workflow.
If WRITING_STYLE_PENDING is yes: ask once about writing style:
v1 prompts are simpler: first-use jargon glosses, outcome-framed questions, shorter prose. Keep default or restore terse?
Options:
A) Keep the new default (recommended — good writing helps everyone)
B) Restore V0 prose — set explain_level: terse
If A: leave explain_level unset (defaults to default).
If B: run ~/.claude/skills/gstack/bin/gstack-config set explain_level terse.
If LAKE_INTRO is no: say "gstack follows the Boil the Ocean principle — do the complete thing when AI makes marginal cost near-zero. Read more: https://garryslist.org/posts/boil-the-ocean" Offer to open:
open https://garryslist.org/posts/boil-the-ocean
touch ~/.gstack/.completeness-intro-seen
Only run open if yes. Always run touch.
If TEL_PROMPTED is no AND LAKE_INTRO is yes: ask telemetry once via AskUserQuestion:
Help gstack get better. Share usage data only: skill, duration, crashes, stable device ID. No code or file paths. Your repo name is recorded locally only and stripped before any upload.
Options:
A) Help gstack get better! (recommended)
B) No thanks
If A: run ~/.claude/skills/gstack/bin/gstack-config set telemetry community
If B: ask follow-up:
Anonymous mode sends only aggregate usage, no unique ID.
Options:
A) Sure, anonymous is fine
B) No thanks, fully off
If B→A: run ~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous
If B→B: run ~/.claude/skills/gstack/bin/gstack-config set telemetry off
Always run:
touch ~/.gstack/.telemetry-prompted
Skip if TEL_PROMPTED is yes.
If PROACTIVE_PROMPTED is no AND TEL_PROMPTED is yes: ask once:
Let gstack proactively suggest skills, like /qa for "does this work?" or /investigate for bugs?
Options:
A) Keep it on (recommended)
B) Turn it off — I'll type /commands myself
If A: run ~/.claude/skills/gstack/bin/gstack-config set proactive true
If B: run ~/.claude/skills/gstack/bin/gstack-config set proactive false
Always run:
touch ~/.gstack/.proactive-prompted
Skip if PROACTIVE_PROMPTED is yes.
First-run guidance (one-time)
If ACTIVATED is no (first skill run on this machine) AND the preamble printed a non-empty FIRST_TASK: value that is NOT nongit: show ONE short, project-specific line mapped from the token, as a heads-up, then CONTINUE with whatever the user actually asked — do NOT halt their task. Map the token: greenfield → "Fresh repo — shape it first with /spec or /office-hours." code_node/code_python/code_rust/code_go/code_ruby/code_ios → "There's code here — /qa to see it work, or /investigate if something's off." branch_ahead → "Unshipped work on this branch — /review then /ship." dirty_default → "Uncommitted changes — /review before committing." clean_default → "Pick one: /spec, /investigate, or /qa." Then substitute the token you saw for TASK_TOKEN and run (best-effort), and mark activated:
If ACTIVATED is no but FIRST_TASK: is empty or nongit (headless, non-git, or nothing actionable): show nothing, just run touch ~/.gstack/.activated 2>/dev/null || true.
Else if ACTIVATED is yes AND FIRST_LOOP_SHOWN is no: say once as a heads-up (then continue):
Tip: gstack pays off when you complete one loop — plan → review → ship. A common first loop: /office-hours or /spec to shape it, /plan-eng-review to lock it, then /ship.
Then run touch ~/.gstack/.first-loop-tip-shown 2>/dev/null || true.
Skip this section if ACTIVATED and FIRST_LOOP_SHOWN are both yes.
If HAS_ROUTING is no AND ROUTING_DECLINED is false AND PROACTIVE_PROMPTED is yes:
Check if a CLAUDE.md file exists in the project root. If it does not exist, create it.
Use AskUserQuestion:
gstack works best when your project's CLAUDE.md includes skill routing rules.
Options:
A) Add routing rules to CLAUDE.md (recommended)
B) No thanks, I'll invoke skills manually
If A: Append this section to the end of CLAUDE.md:
## Skill routing
When the user's request matches an available skill, invoke it via the Skill tool. When in doubt, invoke the skill.
Key routing rules:
- Product ideas/brainstorming → invoke /office-hours
- Strategy/scope → invoke /plan-ceo-review
- Architecture → invoke /plan-eng-review
- Design system/plan review → invoke /design-consultation or /plan-design-review
- Full review pipeline → invoke /autoplan
- Bugs/errors → invoke /investigate
- QA/testing site behavior → invoke /qa or /qa-only
- Code review/diff check → invoke /review
- Visual polish → invoke /design-review
- Ship/deploy/PR → invoke /ship or /land-and-deploy
- Save progress → invoke /context-save
- Resume context → invoke /context-restore
- Author a backlog-ready spec/issue → invoke /spec
Then commit the change: git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"
If B: run ~/.claude/skills/gstack/bin/gstack-config set routing_declined true and say they can re-enable with gstack-config set routing_declined false.
This only happens once per project. Skip if HAS_ROUTING is yes or ROUTING_DECLINED is true.
If VENDORED_GSTACK is yes, warn once via AskUserQuestion unless ~/.gstack/.vendoring-warned-$SLUG exists:
This project has gstack vendored in .claude/skills/gstack/. Vendoring is deprecated.
Migrate to team mode?
Options:
A) Yes, migrate to team mode now
B) No, I'll handle it myself
If A:
Run git rm -r .claude/skills/gstack/
Run echo '.claude/skills/gstack/' >> .gitignore
Run ~/.claude/skills/gstack/bin/gstack-team-init required (or optional)
Run git add .claude/ .gitignore CLAUDE.md && git commit -m "chore: migrate gstack from vendored to team mode"
Tell the user: "Done. Each developer now runs: cd ~/.claude/skills/gstack && ./setup --team"
If B: say "OK, you're on your own to keep the vendored copy up to date."
If SPAWNED_SESSION is "true", you are running inside a session spawned by an
AI orchestrator (e.g., OpenClaw). In spawned sessions:
Do NOT use AskUserQuestion for interactive prompts. Auto-choose the recommended option.
Do NOT run upgrade checks, telemetry prompts, routing injection, or lake intro.
Focus on completing the task and reporting results via prose output.
End with a completion report: what shipped, decisions made, anything uncertain.
Artifacts Sync (skill start)
_GSTACK_HOME="${GSTACK_HOME:-$HOME/.gstack}"# Prefer the v1.27.0.0 artifacts file; fall back to brain file for users# upgrading mid-stream before the migration script runs.if [ -f "$HOME/.gstack-artifacts-remote.txt" ]; then
_BRAIN_REMOTE_FILE="$HOME/.gstack-artifacts-remote.txt"else
_BRAIN_REMOTE_FILE="$HOME/.gstack-brain-remote.txt"fi
_BRAIN_SYNC_BIN="$HOME/.claude/skills/gstack/bin/gstack-brain-sync"
_BRAIN_CONFIG_BIN="$HOME/.claude/skills/gstack/bin/gstack-config"# /sync-gbrain context-load: teach the agent to use gbrain when it's available.# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the# git toplevel to scope queries. Look for the pin in the worktree (not a global# state file) so that opening worktree B without a pin doesn't claim "indexed"# just because worktree A was synced. Empty string when gbrain is not# configured (zero context cost for non-gbrain users).
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
_GBRAIN_PIN_PATH=""
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo"")
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"fiif [ -n "$_GBRAIN_PIN_PATH" ]; thenecho"GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"echo"semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"echo"symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."echo"Run /sync-gbrain to refresh."elseecho"GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"echo"before relying on \`gbrain search\` for code questions in this worktree."echo"Falls back to Grep until pinned."fififi
_BRAIN_SYNC_MODE=$("$_BRAIN_CONFIG_BIN" get artifacts_sync_mode 2>/dev/null || echo off)
# Detect remote-MCP mode (Path 4 of /setup-gbrain). Local artifacts sync is# a no-op in remote mode; the brain server pulls from GitHub/GitLab on its# own cadence. Read claude.json directly to keep this preamble fast (no# subprocess to claude CLI on every skill start). Both registration scopes# are read (#2499): user scope, then the nearest-ancestor project scope.
_GBRAIN_MCP_MODE="none"
_GBRAIN_MCP_ENTRY=""ifcommand -v jq >/dev/null 2>&1 && [ -f "$HOME/.claude.json" ]; then
_GBRAIN_MCP_ENTRY=$(jq -c --arg cwd "$PWD"'.mcpServers.gbrain // ((.projects // {}) | to_entries | map(select((.key as $k | $cwd == $k or ($cwd | startswith($k + "/"))) and ((try .value.mcpServers.gbrain catch null) != null))) | sort_by(.key | length) | last | .value.mcpServers.gbrain) // empty'"$HOME/.claude.json" 2>/dev/null)
_GBRAIN_MCP_TYPE=$(printf'%s'"$_GBRAIN_MCP_ENTRY" | jq -r '.type // .transport // empty' 2>/dev/null)
case"$_GBRAIN_MCP_TYPE"in
url|http|sse) _GBRAIN_MCP_MODE="remote-http" ;;
stdio) _GBRAIN_MCP_MODE="local-stdio" ;;
esacfiif [ -f "$_BRAIN_REMOTE_FILE" ] && [ ! -d "$_GSTACK_HOME/.git" ] && [ "$_BRAIN_SYNC_MODE" = "off" ]; then
_BRAIN_NEW_URL=$(head -1 "$_BRAIN_REMOTE_FILE" 2>/dev/null | tr -d '[:space:]')
if [ -n "$_BRAIN_NEW_URL" ]; thenecho"ARTIFACTS_SYNC: artifacts repo detected: $_BRAIN_NEW_URL"echo"ARTIFACTS_SYNC: run 'gstack-brain-restore' to pull your cross-machine artifacts (or 'gstack-config set artifacts_sync_mode off' to dismiss forever)"fifiif [ -d "$_GSTACK_HOME/.git" ] && [ "$_BRAIN_SYNC_MODE" != "off" ]; then
_BRAIN_LAST_PULL_FILE="$_GSTACK_HOME/.brain-last-pull"
_BRAIN_NOW=$(date +%s)
_BRAIN_DO_PULL=1
if [ -f "$_BRAIN_LAST_PULL_FILE" ]; then
_BRAIN_LAST=$(cat"$_BRAIN_LAST_PULL_FILE" 2>/dev/null || echo 0)
case"$_BRAIN_LAST"in''|*[!0-9]*) _BRAIN_LAST=0 ;; esac
_BRAIN_AGE=$(( _BRAIN_NOW - _BRAIN_LAST ))
[ "$_BRAIN_AGE" -lt 86400 ] && _BRAIN_DO_PULL=0
fiif [ "$_BRAIN_DO_PULL" = "1" ]; then
( cd"$_GSTACK_HOME" && git fetch origin >/dev/null 2>&1 && git merge --ff-only "origin/$(git rev-parse --abbrev-ref HEAD)" >/dev/null 2>&1 ) || trueecho"$_BRAIN_NOW" > "$_BRAIN_LAST_PULL_FILE"fi"$_BRAIN_SYNC_BIN" --once 2>/dev/null || truefiif [ "$_GBRAIN_MCP_MODE" = "remote-http" ]; then# Remote-MCP mode: local artifacts sync is a no-op (brain admin's server# pulls from GitHub/GitLab). Show the user this is by design, not broken.
_GBRAIN_HOST=$(printf'%s'"${_GBRAIN_MCP_ENTRY:-}" | jq -r '.url // empty' 2>/dev/null | sed -E 's|^https?://([^/:]+).*|\1|' | head -1 | tr -cd'A-Za-z0-9._-')
echo"ARTIFACTS_SYNC: remote-mode (managed by brain server ${_GBRAIN_HOST:-remote})"elif [ -d "$_GSTACK_HOME/.git" ] && [ "$_BRAIN_SYNC_MODE" != "off" ]; then
_BRAIN_QUEUE_DEPTH=0
[ -f "$_GSTACK_HOME/.brain-queue.jsonl" ] && _BRAIN_QUEUE_DEPTH=$(wc -l < "$_GSTACK_HOME/.brain-queue.jsonl" | tr -d ' ')
_BRAIN_LAST_PUSH="never"
[ -f "$_GSTACK_HOME/.brain-last-push" ] && _BRAIN_LAST_PUSH=$(cat"$_GSTACK_HOME/.brain-last-push" 2>/dev/null || echo never)
echo"ARTIFACTS_SYNC: mode=$_BRAIN_SYNC_MODE | last_push=$_BRAIN_LAST_PUSH | queue=$_BRAIN_QUEUE_DEPTH"elseecho"ARTIFACTS_SYNC: off"fi
Privacy stop-gate: if output shows ARTIFACTS_SYNC: off, artifacts_sync_mode_prompted is false, and gbrain is on PATH or gbrain doctor --fast --json works, ask once:
gstack can publish your artifacts (CEO plans, designs, reports) to a private GitHub repo that GBrain indexes across machines. How much should sync?
The following nudges are tuned for the claude model family. They are
subordinate to skill workflow, STOP points, AskUserQuestion gates, plan-mode
safety, and /ship review gates. If a nudge below conflicts with skill instructions,
the skill wins. Treat these as preferences, not rules.
Todo-list discipline. When working through a multi-step plan, mark each task
complete individually as you finish it. Do not batch-complete at the end. If a task
turns out to be unnecessary, mark it skipped with a one-line reason.
Think before heavy actions. For complex operations (refactors, migrations,
non-trivial new features), briefly state your approach before executing. This lets
the user course-correct cheaply instead of mid-flight.
Dedicated tools over Bash. Prefer Read, Edit, Write, Glob, Grep over shell
equivalents (cat, sed, find, grep). The dedicated tools are cheaper and clearer.
Voice
Direct, concrete, builder-to-builder. Name the file, function, command, and user-visible impact. No filler.
No em dashes. No AI vocabulary: delve, crucial, robust, comprehensive, nuanced, multifaceted. Never corporate or academic. Short paragraphs. End with what to do.
The user has context you do not. Cross-model agreement is a recommendation, not a decision. The user decides.
Completion Status Protocol
When completing a skill workflow, report status using one of:
DONE — completed with evidence.
DONE_WITH_CONCERNS — completed, but list concerns.
BLOCKED — cannot proceed; state blocker and what was tried.
NEEDS_CONTEXT — missing info; state exactly what is needed.
Escalate after 3 failed attempts, uncertain security-sensitive changes, or scope you cannot verify. Format: STATUS, REASON, ATTEMPTED, RECOMMENDATION.
Operational Self-Improvement
Before completing, if you discovered a durable project quirk or command fix that would save 5+ minutes next time, log it:
Replace SKILL_NAME, OUTCOME, and USED_BROWSE before running.
Replace ERROR_MESSAGE with a short description of the error (if outcome is error,
otherwise use empty string ""), and FAILED_STEP with the step name or number where
the failure occurred (if outcome is error, otherwise use empty string "").
Plan Status Footer
Skills that run plan reviews (/plan-*-review, /codex review) include the EXIT PLAN MODE GATE blocking checklist at the end of the skill, which verifies the plan file ends with ## GSTACK REVIEW REPORT before ExitPlanMode is called. Skills that don't run plan reviews (operational skills like /ship, /qa, /review) typically don't operate in plan mode and have no review report to verify; this footer is a no-op for them. Writing the plan file is the one edit allowed in plan mode.
/scrape — pull data from a page
One entry point for getting data off the web. Two paths under the hood:
Match path (~200ms) — if the user's intent matches an existing
browser-skill's triggers, run it via $B skill run <name> and emit
the JSON.
Prototype path (~30s) — no matching skill yet, so drive the page
with $B primitives, return the JSON, and suggest /skillify so the
next call lands on the match path.
Read-only by contract. If the intent implies writing (submitting forms,
clicking buttons that mutate state), refuse and route to /automate.
Step 1 — Determine intent
The user's request after /scrape is the intent. If they did not include
one, ask once:
"What do you want to scrape? Describe it in one line, e.g. 'top stories
on Hacker News' or 'product names + prices on example.com/products'."
Do not ask multiple clarifying questions up front. Any further questions
go in the prototype path where they're cheaper.
Step 2 — Refuse mutating intents
If the intent implies writes — verbs like submit, post, send, log
in, click X, fill the form, delete, create, order, book —
respond:
"/scrape is read-only. For mutating flows, use /automate (browser-skills
Phase 2 P0 in TODOS.md — not yet shipped). Until then, use $B click /
$B fill / $B type directly."
Stop. Do not enter the match or prototype path.
Step 3 — Match phase
List existing browser-skills:
$B skill list
For each skill, $B skill show <name> exposes the full SKILL.md including
triggers:, description:, and host:. Read these and judge whether the
user's intent semantically matches one of them.
A confident match means all three are true:
The intent's domain matches the skill's host (or one of its hostnames)
A triggers: phrase or the description: covers the same data the
intent asks for
The intent does not require args the skill does not declare in args:
If matched, parse any --arg key=value from the intent (or pass none for
zero-arg skills) and run:
$B skill run <name> [--arg key=value ...]
Emit the JSON the skill prints to stdout. Stop.
If matching is ambiguous (two skills could plausibly fit), pick the
narrower-tier one (project > global > bundled — $B skill list shows the
tier). If still ambiguous, fall through to the prototype path rather than
guess wrong.
Step 4 — Prototype phase
No match. Drive the page using $B primitives:
$B goto <url> — navigate to the target. The user's intent usually
names a host or a URL; use it directly.
$B snapshot --text (or $B text) — get a clean text view of the
page to find selectors.
$B html — pull the raw HTML when you need to parse structured data
(lists, tables, repeated rows).
$B links — when the intent is to gather URLs.
Iterate: try a selector, check the output, refine.
Emit the result as JSON on stdout (one document, not pretty-printed).
Use a stable shape — typically { "items": [...], "count": N } or
similar — so downstream consumers can treat it as data.
Step 5 — Skillify nudge
After a successful prototype, append exactly one line:
"Say /skillify to make this a permanent skill (200ms on next call)."
That is the entire nudge. Do not nag, do not list pros, do not push.
Proactive surfacing is a Phase 3 knob (gstack-config browser_skillify_prompts),
not this skill's job.
When the prototype fails
If the page loads but data extraction does not yield a sensible JSON shape
after 3-4 selector attempts:
Report what you tried, what came back, and what's blocking (lazy-loaded,
JS-rendered, paywalled, etc.).
Do NOT write a partial result and call it done.
Do NOT suggest /skillify on a broken prototype.
Ask the user whether they want to (a) try a different selector, (b)
switch to a different page, or (c) stop.
What this skill does NOT do
Mutating actions (use /automate when shipped, or $B primitives directly)
Sources:observed (you found this in the code), user-stated (user told you),
inferred (AI deduction), cross-model (both Claude and Codex agree).
Confidence: 1-10. Be honest. An observed pattern you verified in the code is 8-9.
An inference you're not sure about is 4-5. A user preference they explicitly stated is 10.
files: Include the specific file paths this learning references. This enables
staleness detection: if those files are later deleted, the learning can be flagged.
Only log genuine discoveries. Don't log obvious things. Don't log things the user
already knows. A good test: would this insight save time in a future session? If yes, log it.