benchmark-models
Compares performance metrics of AI models like Claude, GPT, and Gemini to determine the best option for specific tasks.
Install this skill
Security score
The benchmark-models skill was audited on May 10, 2026 and we found 95 security issues across 3 threat categories, including 1 high-severity. Review the findings below before installing.
Categories Tested
Security Issues
Command substitution pattern
| 27 | |
| 28 | ```bash |
| 29 | _UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) |
| 30 | [ -n "$_UPD" ] && echo "$_UPD" || true |
| 31 | mkdir -p ~/.gstack/sessions |
Command substitution pattern
| 31 | mkdir -p ~/.gstack/sessions |
| 32 | touch ~/.gstack/sessions/"$PPID" |
| 33 | _SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ') |
| 34 | find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || true |
| 35 | _PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") |
Command substitution pattern
| 33 | _SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ') |
| 34 | find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || true |
| 35 | _PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") |
| 36 | _PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no") |
| 37 | _BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown") |
Command substitution pattern
| 34 | find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || true |
| 35 | _PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") |
| 36 | _PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no") |
| 37 | _BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown") |
| 38 | echo "BRANCH: $_BRANCH" |
Command substitution pattern
| 35 | _PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") |
| 36 | _PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no") |
| 37 | _BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown") |
| 38 | echo "BRANCH: $_BRANCH" |
| 39 | _SKILL_PREFIX=$(~/.claude/skills/gstack/bin/gstack-config get skill_prefix 2>/dev/null || echo "false") |
Command substitution pattern
| 37 | _BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown") |
| 38 | echo "BRANCH: $_BRANCH" |
| 39 | _SKILL_PREFIX=$(~/.claude/skills/gstack/bin/gstack-config get skill_prefix 2>/dev/null || echo "false") |
| 40 | echo "PROACTIVE: $_PROACTIVE" |
| 41 | echo "PROACTIVE_PROMPTED: $_PROACTIVE_PROMPTED" |
Command substitution pattern
| 44 | REPO_MODE=${REPO_MODE:-unknown} |
| 45 | echo "REPO_MODE: $REPO_MODE" |
| 46 | _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") |
| 47 | echo "LAKE_INTRO: $_LAKE_SEEN" |
| 48 | _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) |
Command substitution pattern
| 46 | _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") |
| 47 | echo "LAKE_INTRO: $_LAKE_SEEN" |
| 48 | _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) |
| 49 | _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") |
| 50 | _TEL_START=$(date +%s) |
Command substitution pattern
| 47 | echo "LAKE_INTRO: $_LAKE_SEEN" |
| 48 | _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) |
| 49 | _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") |
| 50 | _TEL_START=$(date +%s) |
| 51 | _SESSION_ID="$$-$(date +%s)" |
Command substitution pattern
| 52 | echo "TELEMETRY: ${_TEL:-off}" |
| 53 | echo "TEL_PROMPTED: $_TEL_PROMPTED" |
| 54 | _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") |
| 55 | if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi |
| 56 | echo "EXPLAIN_LEVEL: $_EXPLAIN_LEVEL" |
Command substitution pattern
| 55 | if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi |
| 56 | echo "EXPLAIN_LEVEL: $_EXPLAIN_LEVEL" |
| 57 | _QUESTION_TUNING=$(~/.claude/skills/gstack/bin/gstack-config get question_tuning 2>/dev/null || echo "false") |
| 58 | echo "QUESTION_TUNING: $_QUESTION_TUNING" |
| 59 | mkdir -p ~/.gstack/analytics |
Command substitution pattern
| 59 | mkdir -p ~/.gstack/analytics |
| 60 | if [ "$_TEL" != "off" ]; then |
| 61 | echo '{"skill":"benchmark-models","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true |
| 62 | fi |
| 63 | for _PF in $(find ~/.gstack/analytics -maxdepth 1 -name '.pending-*' 2>/dev/null); do |
Command substitution pattern
| 61 | echo '{"skill":"benchmark-models","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true |
| 62 | fi |
| 63 | for _PF in $(find ~/.gstack/analytics -maxdepth 1 -name '.pending-*' 2>/dev/null); do |
| 64 | if [ -f "$_PF" ]; then |
| 65 | if [ "$_TEL" != "off" ] && [ -x "~/.claude/skills/gstack/bin/gstack-telemetry-log" ]; then |
Command substitution pattern
| 70 | break |
| 71 | done |
| 72 | eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" 2>/dev/null || true |
| 73 | _LEARN_FILE="${GSTACK_HOME:-$HOME/.gstack}/projects/${SLUG:-unknown}/learnings.jsonl" |
| 74 | if [ -f "$_LEARN_FILE" ]; then |
Command substitution pattern
| 73 | _LEARN_FILE="${GSTACK_HOME:-$HOME/.gstack}/projects/${SLUG:-unknown}/learnings.jsonl" |
| 74 | if [ -f "$_LEARN_FILE" ]; then |
| 75 | _LEARN_COUNT=$(wc -l < "$_LEARN_FILE" 2>/dev/null | tr -d ' ') |
| 76 | echo "LEARNINGS: $_LEARN_COUNT entries loaded" |
| 77 | if [ "$_LEARN_COUNT" -gt 5 ] 2>/dev/null; then |
Command substitution pattern
| 86 | _HAS_ROUTING="yes" |
| 87 | fi |
| 88 | _ROUTING_DECLINED=$(~/.claude/skills/gstack/bin/gstack-config get routing_declined 2>/dev/null || echo "false") |
| 89 | echo "HAS_ROUTING: $_HAS_ROUTING" |
| 90 | echo "ROUTING_DECLINED: $_ROUTING_DECLINED" |
Command substitution pattern
| 97 | echo "VENDORED_GSTACK: $_VENDORED" |
| 98 | echo "MODEL_OVERLAY: claude" |
| 99 | _CHECKPOINT_MODE=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_mode 2>/dev/null || echo "explicit") |
| 100 | _CHECKPOINT_PUSH=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_push 2>/dev/null || echo "false") |
| 101 | echo "CHECKPOINT_MODE: $_CHECKPOINT_MODE" |
Command substitution pattern
| 98 | echo "MODEL_OVERLAY: claude" |
| 99 | _CHECKPOINT_MODE=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_mode 2>/dev/null || echo "explicit") |
| 100 | _CHECKPOINT_PUSH=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_push 2>/dev/null || echo "false") |
| 101 | echo "CHECKPOINT_MODE: $_CHECKPOINT_MODE" |
| 102 | echo "CHECKPOINT_PUSH: $_CHECKPOINT_PUSH" |
Command substitution pattern
| 260 | Always run (regardless of choice): |
| 261 | ```bash |
| 262 | eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" 2>/dev/null || true |
| 263 | touch ~/.gstack/.vendoring-warned-${SLUG:-unknown} |
| 264 | ``` |
Command substitution pattern
| 295 | _GBRAIN_CONFIG="$HOME/.gbrain/config.json" |
| 296 | if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then |
| 297 | _GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0) |
| 298 | if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then |
| 299 | _GBRAIN_PIN_PATH="" |
Command substitution pattern
| 298 | if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then |
| 299 | _GBRAIN_PIN_PATH="" |
| 300 | _REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "") |
| 301 | if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then |
| 302 | _GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source" |
Command substitution pattern
| 315 | fi |
| 316 | |
| 317 | _BRAIN_SYNC_MODE=$("$_BRAIN_CONFIG_BIN" get artifacts_sync_mode 2>/dev/null || echo off) |
| 318 | |
| 319 | # Detect remote-MCP mode (Path 4 of /setup-gbrain). Local artifacts sync is |
Command substitution pattern
| 323 | _GBRAIN_MCP_MODE="none" |
| 324 | if command -v jq >/dev/null 2>&1 && [ -f "$HOME/.claude.json" ]; then |
| 325 | _GBRAIN_MCP_TYPE=$(jq -r '.mcpServers.gbrain.type // .mcpServers.gbrain.transport // empty' "$HOME/.claude.json" 2>/dev/null) |
| 326 | case "$_GBRAIN_MCP_TYPE" in |
| 327 | url|http|sse) _GBRAIN_MCP_MODE="remote-http" ;; |
Command substitution pattern
| 331 | |
| 332 | if [ -f "$_BRAIN_REMOTE_FILE" ] && [ ! -d "$_GSTACK_HOME/.git" ] && [ "$_BRAIN_SYNC_MODE" = "off" ]; then |
| 333 | _BRAIN_NEW_URL=$(head -1 "$_BRAIN_REMOTE_FILE" 2>/dev/null | tr -d '[:space:]') |
| 334 | if [ -n "$_BRAIN_NEW_URL" ]; then |
| 335 | echo "ARTIFACTS_SYNC: artifacts repo detected: $_BRAIN_NEW_URL" |
Command substitution pattern
| 343 | _BRAIN_DO_PULL=1 |
| 344 | if [ -f "$_BRAIN_LAST_PULL_FILE" ]; then |
| 345 | _BRAIN_LAST=$(cat "$_BRAIN_LAST_PULL_FILE" 2>/dev/null || echo 0) |
| 346 | _BRAIN_AGE=$(( _BRAIN_NOW - _BRAIN_LAST )) |
| 347 | [ "$_BRAIN_AGE" -lt 86400 ] && _BRAIN_DO_PULL=0 |
Command substitution pattern
| 344 | if [ -f "$_BRAIN_LAST_PULL_FILE" ]; then |
| 345 | _BRAIN_LAST=$(cat "$_BRAIN_LAST_PULL_FILE" 2>/dev/null || echo 0) |
| 346 | _BRAIN_AGE=$(( _BRAIN_NOW - _BRAIN_LAST )) |
| 347 | [ "$_BRAIN_AGE" -lt 86400 ] && _BRAIN_DO_PULL=0 |
| 348 | fi |
Command substitution pattern
| 348 | fi |
| 349 | if [ "$_BRAIN_DO_PULL" = "1" ]; then |
| 350 | ( 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 ) || true |
| 351 | echo "$_BRAIN_NOW" > "$_BRAIN_LAST_PULL_FILE" |
| 352 | fi |
Command substitution pattern
| 357 | # Remote-MCP mode: local artifacts sync is a no-op (brain admin's server |
| 358 | # pulls from GitHub/GitLab). Show the user this is by design, not broken. |
| 359 | _GBRAIN_HOST=$(jq -r '.mcpServers.gbrain.url // empty' "$HOME/.claude.json" 2>/dev/null | sed -E 's|^https?://([^/:]+).*|\1|') |
| 360 | echo "ARTIFACTS_SYNC: remote-mode (managed by brain server ${_GBRAIN_HOST:-remote})" |
| 361 | elif [ -d "$_GSTACK_HOME/.git" ] && [ "$_BRAIN_SYNC_MODE" != "off" ]; then |
Command substitution pattern
| 361 | elif [ -d "$_GSTACK_HOME/.git" ] && [ "$_BRAIN_SYNC_MODE" != "off" ]; then |
| 362 | _BRAIN_QUEUE_DEPTH=0 |
| 363 | [ -f "$_GSTACK_HOME/.brain-queue.jsonl" ] && _BRAIN_QUEUE_DEPTH=$(wc -l < "$_GSTACK_HOME/.brain-queue.jsonl" | tr -d ' ') |
| 364 | _BRAIN_LAST_PUSH="never" |
| 365 | [ -f "$_GSTACK_HOME/.brain-last-push" ] && _BRAIN_LAST_PUSH=$(cat "$_GSTACK_HOME/.brain-last-push" 2>/dev/null || echo never) |
Command substitution pattern
| 363 | [ -f "$_GSTACK_HOME/.brain-queue.jsonl" ] && _BRAIN_QUEUE_DEPTH=$(wc -l < "$_GSTACK_HOME/.brain-queue.jsonl" | tr -d ' ') |
| 364 | _BRAIN_LAST_PUSH="never" |
| 365 | [ -f "$_GSTACK_HOME/.brain-last-push" ] && _BRAIN_LAST_PUSH=$(cat "$_GSTACK_HOME/.brain-last-push" 2>/dev/null || echo never) |
| 366 | echo "ARTIFACTS_SYNC: mode=$_BRAIN_SYNC_MODE | last_push=$_BRAIN_LAST_PUSH | queue=$_BRAIN_QUEUE_DEPTH" |
| 367 | else |
Command substitution pattern
| 456 | ```bash |
| 457 | _TEL_END=$(date +%s) |
| 458 | _TEL_DUR=$(( _TEL_END - _TEL_START )) |
| 459 | rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true |
| 460 | # Session timeline: record skill completion (local-only, never sent anywhere) |
Command substitution pattern
| 459 | rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true |
| 460 | # Session timeline: record skill completion (local-only, never sent anywhere) |
| 461 | ~/.claude/skills/gstack/bin/gstack-timeline-log '{"skill":"SKILL_NAME","event":"completed","branch":"'$(git branch --show-current 2>/dev/null || echo unknown)'","outcome":"OUTCOME","duration_s":"'"$_TEL_DUR"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null || true |
| 462 | # Local analytics (gated on telemetry setting) |
| 463 | if [ "$_TEL" != "off" ]; then |
Command substitution pattern
| 462 | # Local analytics (gated on telemetry setting) |
| 463 | if [ "$_TEL" != "off" ]; then |
| 464 | echo '{"skill":"SKILL_NAME","duration_s":"'"$_TEL_DUR"'","outcome":"OUTCOME","browse":"USED_BROWSE","session":"'"$_SESSION_ID"'","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true |
| 465 | fi |
| 466 | # Remote telemetry (opt-in, requires binary) |
Access to home directory dotfiles
| 27 | |
| 28 | ```bash |
| 29 | _UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) |
| 30 | [ -n "$_UPD" ] && echo "$_UPD" || true |
| 31 | mkdir -p ~/.gstack/sessions |
Access to home directory dotfiles
| 29 | _UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true) |
| 30 | [ -n "$_UPD" ] && echo "$_UPD" || true |
| 31 | mkdir -p ~/.gstack/sessions |
| 32 | touch ~/.gstack/sessions/"$PPID" |
| 33 | _SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ') |
Access to home directory dotfiles
| 30 | [ -n "$_UPD" ] && echo "$_UPD" || true |
| 31 | mkdir -p ~/.gstack/sessions |
| 32 | touch ~/.gstack/sessions/"$PPID" |
| 33 | _SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ') |
| 34 | find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || true |
Access to home directory dotfiles
| 31 | mkdir -p ~/.gstack/sessions |
| 32 | touch ~/.gstack/sessions/"$PPID" |
| 33 | _SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ') |
| 34 | find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || true |
| 35 | _PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") |
Access to home directory dotfiles
| 32 | touch ~/.gstack/sessions/"$PPID" |
| 33 | _SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ') |
| 34 | find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || true |
| 35 | _PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") |
| 36 | _PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no") |
Access to home directory dotfiles
| 33 | _SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ') |
| 34 | find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || true |
| 35 | _PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") |
| 36 | _PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no") |
| 37 | _BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown") |
Access to home directory dotfiles
| 34 | find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || true |
| 35 | _PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true") |
| 36 | _PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no") |
| 37 | _BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown") |
| 38 | echo "BRANCH: $_BRANCH" |
Access to home directory dotfiles
| 37 | _BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown") |
| 38 | echo "BRANCH: $_BRANCH" |
| 39 | _SKILL_PREFIX=$(~/.claude/skills/gstack/bin/gstack-config get skill_prefix 2>/dev/null || echo "false") |
| 40 | echo "PROACTIVE: $_PROACTIVE" |
| 41 | echo "PROACTIVE_PROMPTED: $_PROACTIVE_PROMPTED" |
Access to home directory dotfiles
| 41 | echo "PROACTIVE_PROMPTED: $_PROACTIVE_PROMPTED" |
| 42 | echo "SKILL_PREFIX: $_SKILL_PREFIX" |
| 43 | source <(~/.claude/skills/gstack/bin/gstack-repo-mode 2>/dev/null) || true |
| 44 | REPO_MODE=${REPO_MODE:-unknown} |
| 45 | echo "REPO_MODE: $REPO_MODE" |
Access to home directory dotfiles
| 44 | REPO_MODE=${REPO_MODE:-unknown} |
| 45 | echo "REPO_MODE: $REPO_MODE" |
| 46 | _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") |
| 47 | echo "LAKE_INTRO: $_LAKE_SEEN" |
| 48 | _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) |
Access to home directory dotfiles
| 46 | _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") |
| 47 | echo "LAKE_INTRO: $_LAKE_SEEN" |
| 48 | _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) |
| 49 | _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") |
| 50 | _TEL_START=$(date +%s) |
Access to home directory dotfiles
| 47 | echo "LAKE_INTRO: $_LAKE_SEEN" |
| 48 | _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) |
| 49 | _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") |
| 50 | _TEL_START=$(date +%s) |
| 51 | _SESSION_ID="$$-$(date +%s)" |
Access to home directory dotfiles
| 52 | echo "TELEMETRY: ${_TEL:-off}" |
| 53 | echo "TEL_PROMPTED: $_TEL_PROMPTED" |
| 54 | _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") |
| 55 | if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi |
| 56 | echo "EXPLAIN_LEVEL: $_EXPLAIN_LEVEL" |
Access to home directory dotfiles
| 55 | if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi |
| 56 | echo "EXPLAIN_LEVEL: $_EXPLAIN_LEVEL" |
| 57 | _QUESTION_TUNING=$(~/.claude/skills/gstack/bin/gstack-config get question_tuning 2>/dev/null || echo "false") |
| 58 | echo "QUESTION_TUNING: $_QUESTION_TUNING" |
| 59 | mkdir -p ~/.gstack/analytics |
Access to home directory dotfiles
| 57 | _QUESTION_TUNING=$(~/.claude/skills/gstack/bin/gstack-config get question_tuning 2>/dev/null || echo "false") |
| 58 | echo "QUESTION_TUNING: $_QUESTION_TUNING" |
| 59 | mkdir -p ~/.gstack/analytics |
| 60 | if [ "$_TEL" != "off" ]; then |
| 61 | echo '{"skill":"benchmark-models","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true |
Access to home directory dotfiles
| 59 | mkdir -p ~/.gstack/analytics |
| 60 | if [ "$_TEL" != "off" ]; then |
| 61 | echo '{"skill":"benchmark-models","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true |
| 62 | fi |
| 63 | for _PF in $(find ~/.gstack/analytics -maxdepth 1 -name '.pending-*' 2>/dev/null); do |
Access to home directory dotfiles
| 61 | echo '{"skill":"benchmark-models","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true |
| 62 | fi |
| 63 | for _PF in $(find ~/.gstack/analytics -maxdepth 1 -name '.pending-*' 2>/dev/null); do |
| 64 | if [ -f "$_PF" ]; then |
| 65 | if [ "$_TEL" != "off" ] && [ -x "~/.claude/skills/gstack/bin/gstack-telemetry-log" ]; then |
Access to home directory dotfiles
| 63 | for _PF in $(find ~/.gstack/analytics -maxdepth 1 -name '.pending-*' 2>/dev/null); do |
| 64 | if [ -f "$_PF" ]; then |
| 65 | if [ "$_TEL" != "off" ] && [ -x "~/.claude/skills/gstack/bin/gstack-telemetry-log" ]; then |
| 66 | ~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true |
| 67 | fi |
Access to home directory dotfiles
| 64 | if [ -f "$_PF" ]; then |
| 65 | if [ "$_TEL" != "off" ] && [ -x "~/.claude/skills/gstack/bin/gstack-telemetry-log" ]; then |
| 66 | ~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true |
| 67 | fi |
| 68 | rm -f "$_PF" 2>/dev/null || true |
Access to home directory dotfiles
| 70 | break |
| 71 | done |
| 72 | eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" 2>/dev/null || true |
| 73 | _LEARN_FILE="${GSTACK_HOME:-$HOME/.gstack}/projects/${SLUG:-unknown}/learnings.jsonl" |
| 74 | if [ -f "$_LEARN_FILE" ]; then |
Access to home directory dotfiles
| 76 | echo "LEARNINGS: $_LEARN_COUNT entries loaded" |
| 77 | if [ "$_LEARN_COUNT" -gt 5 ] 2>/dev/null; then |
| 78 | ~/.claude/skills/gstack/bin/gstack-learnings-search --limit 3 2>/dev/null || true |
| 79 | fi |
| 80 | else |
Access to home directory dotfiles
| 81 | echo "LEARNINGS: 0" |
| 82 | fi |
| 83 | ~/.claude/skills/gstack/bin/gstack-timeline-log '{"skill":"benchmark-models","event":"started","branch":"'"$_BRANCH"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null & |
| 84 | _HAS_ROUTING="no" |
| 85 | if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then |
Access to home directory dotfiles
| 86 | _HAS_ROUTING="yes" |
| 87 | fi |
| 88 | _ROUTING_DECLINED=$(~/.claude/skills/gstack/bin/gstack-config get routing_declined 2>/dev/null || echo "false") |
| 89 | echo "HAS_ROUTING: $_HAS_ROUTING" |
| 90 | echo "ROUTING_DECLINED: $_ROUTING_DECLINED" |
Access to home directory dotfiles
| 97 | echo "VENDORED_GSTACK: $_VENDORED" |
| 98 | echo "MODEL_OVERLAY: claude" |
| 99 | _CHECKPOINT_MODE=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_mode 2>/dev/null || echo "explicit") |
| 100 | _CHECKPOINT_PUSH=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_push 2>/dev/null || echo "false") |
| 101 | echo "CHECKPOINT_MODE: $_CHECKPOINT_MODE" |
Access to home directory dotfiles
| 98 | echo "MODEL_OVERLAY: claude" |
| 99 | _CHECKPOINT_MODE=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_mode 2>/dev/null || echo "explicit") |
| 100 | _CHECKPOINT_PUSH=$(~/.claude/skills/gstack/bin/gstack-config get checkpoint_push 2>/dev/null || echo "false") |
| 101 | echo "CHECKPOINT_MODE: $_CHECKPOINT_MODE" |
| 102 | echo "CHECKPOINT_PUSH: $_CHECKPOINT_PUSH" |
Access to home directory dotfiles
| 106 | ## Plan Mode Safe Operations |
| 107 | |
| 108 | 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. |
| 109 | |
| 110 | ## Skill Invocation During Plan Mode |
Access to home directory dotfiles
| 114 | 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?" |
| 115 | |
| 116 | If `SKILL_PREFIX` is `"true"`, suggest/invoke `/gstack-*` names. Disk paths stay `~/.claude/skills/gstack/[skill-name]/SKILL.md`. |
| 117 | |
| 118 | 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). |
Access to home directory dotfiles
| 116 | If `SKILL_PREFIX` is `"true"`, suggest/invoke `/gstack-*` names. Disk paths stay `~/.claude/skills/gstack/[skill-name]/SKILL.md`. |
| 117 | |
| 118 | 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). |
| 119 | |
| 120 | If output shows `JUST_UPGRADED <from> <to>`: print "Running gstack v{to} (just updated!)". If `SPAWNED_SESSION` is true, skip feature discovery. |
Access to home directory dotfiles
| 121 | |
| 122 | Feature discovery, max one prompt per session: |
| 123 | - 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. |
| 124 | - Missing `~/.claude/skills/gstack/.feature-prompted-model-overlay`: inform "Model overlays are active. MODEL_OVERLAY shows the patch." Always touch marker. |
| 125 |
Access to home directory dotfiles
| 122 | Feature discovery, max one prompt per session: |
| 123 | - 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. |
| 124 | - Missing `~/.claude/skills/gstack/.feature-prompted-model-overlay`: inform "Model overlays are active. MODEL_OVERLAY shows the patch." Always touch marker. |
| 125 | |
| 126 | After upgrade prompts, continue workflow. |
Access to home directory dotfiles
| 135 | |
| 136 | If A: leave `explain_level` unset (defaults to `default`). |
| 137 | If B: run `~/.claude/skills/gstack/bin/gstack-config set explain_level terse`. |
| 138 | |
| 139 | Always run (regardless of choice): |
Access to home directory dotfiles
| 139 | Always run (regardless of choice): |
| 140 | ```bash |
| 141 | rm -f ~/.gstack/.writing-style-prompt-pending |
| 142 | touch ~/.gstack/.writing-style-prompted |
| 143 | ``` |
Access to home directory dotfiles
| 140 | ```bash |
| 141 | rm -f ~/.gstack/.writing-style-prompt-pending |
| 142 | touch ~/.gstack/.writing-style-prompted |
| 143 | ``` |
| 144 |
Access to home directory dotfiles
| 149 | ```bash |
| 150 | open https://garryslist.org/posts/boil-the-ocean |
| 151 | touch ~/.gstack/.completeness-intro-seen |
| 152 | ``` |
| 153 |
Access to home directory dotfiles
| 162 | - B) No thanks |
| 163 | |
| 164 | If A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry community` |
| 165 | |
| 166 | If B: ask follow-up: |
Access to home directory dotfiles
| 172 | - B) No thanks, fully off |
| 173 | |
| 174 | If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` |
| 175 | If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` |
| 176 |
Access to home directory dotfiles
| 173 | |
| 174 | If B→A: run `~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous` |
| 175 | If B→B: run `~/.claude/skills/gstack/bin/gstack-config set telemetry off` |
| 176 | |
| 177 | Always run: |
Access to home directory dotfiles
| 177 | Always run: |
| 178 | ```bash |
| 179 | touch ~/.gstack/.telemetry-prompted |
| 180 | ``` |
| 181 |
Access to home directory dotfiles
| 190 | - B) Turn it off — I'll type /commands myself |
| 191 | |
| 192 | If A: run `~/.claude/skills/gstack/bin/gstack-config set proactive true` |
| 193 | If B: run `~/.claude/skills/gstack/bin/gstack-config set proactive false` |
| 194 |
Access to home directory dotfiles
| 191 | |
| 192 | If A: run `~/.claude/skills/gstack/bin/gstack-config set proactive true` |
| 193 | If B: run `~/.claude/skills/gstack/bin/gstack-config set proactive false` |
| 194 | |
| 195 | Always run: |
Access to home directory dotfiles
| 195 | Always run: |
| 196 | ```bash |
| 197 | touch ~/.gstack/.proactive-prompted |
| 198 | ``` |
| 199 |
Access to home directory dotfiles
| 236 | Then commit the change: `git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"` |
| 237 | |
| 238 | 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`. |
| 239 | |
| 240 | This only happens once per project. Skip if `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`. |
Access to home directory dotfiles
| 240 | This only happens once per project. Skip if `HAS_ROUTING` is `yes` or `ROUTING_DECLINED` is `true`. |
| 241 | |
| 242 | If `VENDORED_GSTACK` is `yes`, warn once via AskUserQuestion unless `~/.gstack/.vendoring-warned-$SLUG` exists: |
| 243 | |
| 244 | > This project has gstack vendored in `.claude/skills/gstack/`. Vendoring is deprecated. |
Access to home directory dotfiles
| 252 | 1. Run `git rm -r .claude/skills/gstack/` |
| 253 | 2. Run `echo '.claude/skills/gstack/' >> .gitignore` |
| 254 | 3. Run `~/.claude/skills/gstack/bin/gstack-team-init required` (or `optional`) |
| 255 | 4. Run `git add .claude/ .gitignore CLAUDE.md && git commit -m "chore: migrate gstack from vendored to team mode"` |
| 256 | 5. Tell the user: "Done. Each developer now runs: `cd ~/.claude/skills/gstack && ./setup --team`" |
Access to home directory dotfiles
| 254 | 3. Run `~/.claude/skills/gstack/bin/gstack-team-init required` (or `optional`) |
| 255 | 4. Run `git add .claude/ .gitignore CLAUDE.md && git commit -m "chore: migrate gstack from vendored to team mode"` |
| 256 | 5. Tell the user: "Done. Each developer now runs: `cd ~/.claude/skills/gstack && ./setup --team`" |
| 257 | |
| 258 | If B: say "OK, you're on your own to keep the vendored copy up to date." |
Access to home directory dotfiles
| 260 | Always run (regardless of choice): |
| 261 | ```bash |
| 262 | eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" 2>/dev/null || true |
| 263 | touch ~/.gstack/.vendoring-warned-${SLUG:-unknown} |
| 264 | ``` |
Access to home directory dotfiles
| 261 | ```bash |
| 262 | eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" 2>/dev/null || true |
| 263 | touch ~/.gstack/.vendoring-warned-${SLUG:-unknown} |
| 264 | ``` |
| 265 |
Access to home directory dotfiles
| 284 | _BRAIN_REMOTE_FILE="$HOME/.gstack-brain-remote.txt" |
| 285 | fi |
| 286 | _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync" |
| 287 | _BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config" |
| 288 |
Access to home directory dotfiles
| 285 | fi |
| 286 | _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync" |
| 287 | _BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config" |
| 288 | |
| 289 | # /sync-gbrain context-load: teach the agent to use gbrain when it's available. |
Access to home directory dotfiles
| 389 | ``` |
| 390 | |
| 391 | If A/B and `~/.gstack/.git` is missing, ask whether to run `gstack-artifacts-init`. Do not block the skill. |
| 392 | |
| 393 | At skill END before telemetry: |
Access to home directory dotfiles
| 394 | |
| 395 | ```bash |
| 396 | "~/.claude/skills/gstack/bin/gstack-brain-sync" --discover-new 2>/dev/null || true |
| 397 | "~/.claude/skills/gstack/bin/gstack-brain-sync" --once 2>/dev/null || true |
| 398 | ``` |
Access to home directory dotfiles
| 395 | ```bash |
| 396 | "~/.claude/skills/gstack/bin/gstack-brain-sync" --discover-new 2>/dev/null || true |
| 397 | "~/.claude/skills/gstack/bin/gstack-brain-sync" --once 2>/dev/null || true |
| 398 | ``` |
| 399 |
Access to home directory dotfiles
| 440 | |
| 441 | ```bash |
| 442 | ~/.claude/skills/gstack/bin/gstack-learnings-log '{"skill":"SKILL_NAME","type":"operational","key":"SHORT_KEY","insight":"DESCRIPTION","confidence":N,"source":"observed"}' |
| 443 | ``` |
| 444 |
Access to home directory dotfiles
| 450 | |
| 451 | **PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to |
| 452 | `~/.gstack/analytics/`, matching preamble analytics writes. |
| 453 | |
| 454 | Run this bash: |
Access to home directory dotfiles
| 457 | _TEL_END=$(date +%s) |
| 458 | _TEL_DUR=$(( _TEL_END - _TEL_START )) |
| 459 | rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true |
| 460 | # Session timeline: record skill completion (local-only, never sent anywhere) |
| 461 | ~/.claude/skills/gstack/bin/gstack-timeline-log '{"skill":"SKILL_NAME","event":"completed","branch":"'$(git branch --show-current 2>/dev/null || echo unknown)'","outcome":"OUTCOME","duration_s":"'"$_TEL_DUR"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null || true |
Access to home directory dotfiles
| 459 | rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true |
| 460 | # Session timeline: record skill completion (local-only, never sent anywhere) |
| 461 | ~/.claude/skills/gstack/bin/gstack-timeline-log '{"skill":"SKILL_NAME","event":"completed","branch":"'$(git branch --show-current 2>/dev/null || echo unknown)'","outcome":"OUTCOME","duration_s":"'"$_TEL_DUR"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null || true |
| 462 | # Local analytics (gated on telemetry setting) |
| 463 | if [ "$_TEL" != "off" ]; then |
Access to home directory dotfiles
| 462 | # Local analytics (gated on telemetry setting) |
| 463 | if [ "$_TEL" != "off" ]; then |
| 464 | echo '{"skill":"SKILL_NAME","duration_s":"'"$_TEL_DUR"'","outcome":"OUTCOME","browse":"USED_BROWSE","session":"'"$_SESSION_ID"'","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true |
| 465 | fi |
| 466 | # Remote telemetry (opt-in, requires binary) |
Access to home directory dotfiles
| 465 | fi |
| 466 | # Remote telemetry (opt-in, requires binary) |
| 467 | if [ "$_TEL" != "off" ] && [ -x ~/.claude/skills/gstack/bin/gstack-telemetry-log ]; then |
| 468 | ~/.claude/skills/gstack/bin/gstack-telemetry-log \ |
| 469 | --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ |
Access to home directory dotfiles
| 466 | # Remote telemetry (opt-in, requires binary) |
| 467 | if [ "$_TEL" != "off" ] && [ -x ~/.claude/skills/gstack/bin/gstack-telemetry-log ]; then |
| 468 | ~/.claude/skills/gstack/bin/gstack-telemetry-log \ |
| 469 | --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ |
| 470 | --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & |
Access to home directory dotfiles
| 476 | ## Plan Status Footer |
| 477 | |
| 478 | In plan mode before ExitPlanMode: if the plan file lacks `## GSTACK REVIEW REPORT`, run `~/.claude/skills/gstack/bin/gstack-review-read` and append the standard runs/status/findings table. With `NO_REVIEWS` or empty, append a 5-row placeholder with verdict "NO REVIEWS YET — run `/autoplan`". If a richer report exists, skip. |
| 479 | |
| 480 | PLAN MODE EXCEPTION — always allowed (it's the plan file). |
Access to home directory dotfiles
| 589 | - **RECOMMENDATION:** A — skill performance drifts as providers update their models; a saved baseline catches quality regressions. |
| 590 | - **Options:** |
| 591 | - A) Save to `~/.gstack/benchmarks/<date>-<skill-or-prompt-slug>.json`. Completeness: 10/10. |
| 592 | - B) Just print, don't save. Completeness: 5/10 (loses trend data). |
| 593 |
Urgency-based manipulation
| 110 | ## Skill Invocation During Plan Mode |
| 111 | |
| 112 | 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; the first AskUserQuestion is the workflow entering plan mode, not a violation of it. AskUserQuestion (any variant — `mcp__*__AskUserQuestion` or native; see "AskUserQuestion Format → Tool resolution") satisfies plan mode's end-of-turn requirement. If no variant is callable, the skill is BLOCKED — stop and report `BLOCKED — AskUserQuestion unavailable` per the AskUserQuestion Format rule. 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. |
| 113 | |
| 114 | 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?" |