diff --git a/AGENTS.md b/AGENTS.md index 4df7eec35..e3224ff2f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -64,6 +64,7 @@ Invoke them by name (e.g., `/office-hours`). | `/benchmark` | Performance regression detection (page load, Core Web Vitals). | | `/benchmark-models` | Cross-model benchmark for skills (Claude, GPT, Gemini side-by-side). | | `/cso` | OWASP Top 10 + STRIDE security audit. | +| `/setup-search-mcp` | Optional free Search MCP setup for Search Before Building. | | `/setup-gbrain` | Set up gbrain for cross-machine session memory sync. | | `/sync-gbrain` | Keep gbrain current with this repo's code; refresh agent search guidance in CLAUDE.md. | diff --git a/README.md b/README.md index af534d2c5..4c5b1f233 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Fork it. Improve it. Make it yours. And if you want to hate on free open source Open Claude Code and paste this. Claude does the rest. -> Install gstack: run **`git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack && cd ~/.claude/skills/gstack && ./setup`** then add a "gstack" section to CLAUDE.md that says to use the /browse skill from gstack for all web browsing, never use mcp\_\_claude-in-chrome\_\_\* tools, and lists the available skills: /office-hours, /plan-ceo-review, /plan-eng-review, /plan-design-review, /design-consultation, /design-shotgun, /design-html, /review, /ship, /land-and-deploy, /canary, /benchmark, /browse, /connect-chrome, /qa, /qa-only, /design-review, /setup-browser-cookies, /setup-deploy, /setup-gbrain, /retro, /investigate, /document-release, /document-generate, /codex, /cso, /autoplan, /plan-devex-review, /devex-review, /careful, /freeze, /guard, /unfreeze, /gstack-upgrade, /learn. Then ask the user if they also want to add gstack to the current project so teammates get it. +> Install gstack: run **`git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack && cd ~/.claude/skills/gstack && ./setup`** then add a "gstack" section to CLAUDE.md that says to use the /browse skill from gstack for all web browsing, never use mcp\_\_claude-in-chrome\_\_\* tools, and lists the available skills: /office-hours, /plan-ceo-review, /plan-eng-review, /plan-design-review, /design-consultation, /design-shotgun, /design-html, /review, /ship, /land-and-deploy, /canary, /benchmark, /browse, /connect-chrome, /qa, /qa-only, /design-review, /setup-browser-cookies, /setup-deploy, /setup-search-mcp, /setup-gbrain, /retro, /investigate, /document-release, /document-generate, /codex, /cso, /autoplan, /plan-devex-review, /devex-review, /careful, /freeze, /guard, /unfreeze, /gstack-upgrade, /learn. Then ask the user if they also want to add gstack to the current project so teammates get it. ### Step 2: Team mode — auto-update for shared repos (recommended) @@ -229,6 +229,7 @@ Each skill feeds into the next. `/office-hours` writes a design doc that `/plan- | `/unfreeze` | **Unlock** — remove the `/freeze` boundary. | | `/open-gstack-browser` | **GStack Browser** — launch GStack Browser with sidebar, anti-bot stealth, auto model routing (Sonnet for actions, Opus for analysis), one-click cookie import, and Claude Code integration. Clean up pages, take smart screenshots, edit CSS, and pass info back to your terminal. | | `/setup-deploy` | **Deploy Configurator** — one-time setup for `/land-and-deploy`. Detects your platform, production URL, and deploy commands. | +| `/setup-search-mcp` | **Search MCP Setup** — free web search for agents. Adds Parallel Search MCP on supported hosts; no account or API key by default. | | `/setup-gbrain` | **GBrain Onboarding** — from zero to running gbrain in under 5 minutes. PGLite local, Supabase existing URL, or auto-provision a new Supabase project via Management API. MCP registration for Claude Code + per-repo trust triad (read-write/read-only/deny). [Full guide](USING_GBRAIN_WITH_GSTACK.md). | | `/sync-gbrain` | **Keep Brain Current** — re-index this repo's code into gbrain via `gbrain sources add` + `gbrain sync --strategy code`, refresh the `## GBrain Search Guidance` block in CLAUDE.md, and auto-remove guidance when the capability check fails. `--incremental` (default), `--full`, `--dry-run`. Idempotent; safe to re-run. | | `/gstack-upgrade` | **Self-Updater** — upgrade gstack to latest. Detects global vs vendored install, syncs both, shows what changed. | @@ -481,7 +482,7 @@ Use /browse from gstack for all web browsing. Never use mcp__claude-in-chrome__* Available skills: /office-hours, /plan-ceo-review, /plan-eng-review, /plan-design-review, /design-consultation, /design-shotgun, /design-html, /review, /ship, /land-and-deploy, /canary, /benchmark, /browse, /open-gstack-browser, /qa, /qa-only, /design-review, -/setup-browser-cookies, /setup-deploy, /setup-gbrain, /sync-gbrain, /retro, /investigate, +/setup-browser-cookies, /setup-deploy, /setup-search-mcp, /setup-gbrain, /sync-gbrain, /retro, /investigate, /document-release, /document-generate, /codex, /cso, /autoplan, /pair-agent, /careful, /freeze, /guard, /unfreeze, /gstack-upgrade, /learn. ``` diff --git a/SKILL.md b/SKILL.md index aaa5612dd..bc19bebe7 100644 --- a/SKILL.md +++ b/SKILL.md @@ -573,6 +573,7 @@ quality gates that produce better results than answering inline. - User asks to ship, deploy, push, create a PR, "let's land this", "send it" → invoke `/ship` - User asks to merge + deploy + verify as one flow → invoke `/land-and-deploy` - User asks to configure deployment for the project → invoke `/setup-deploy` +- User asks to set up search, install web search MCP, connect Parallel Search MCP, or make Search Before Building work → invoke `/setup-search-mcp` - User asks to monitor prod after shipping, post-deploy checks → invoke `/canary` - User asks to update docs after shipping → invoke `/document-release` - User asks to write docs from scratch, generate documentation, "document this feature/module" → invoke `/document-generate` diff --git a/SKILL.md.tmpl b/SKILL.md.tmpl index 402bd0d7b..c39896c06 100644 --- a/SKILL.md.tmpl +++ b/SKILL.md.tmpl @@ -62,6 +62,7 @@ quality gates that produce better results than answering inline. - User asks to ship, deploy, push, create a PR, "let's land this", "send it" → invoke `/ship` - User asks to merge + deploy + verify as one flow → invoke `/land-and-deploy` - User asks to configure deployment for the project → invoke `/setup-deploy` +- User asks to set up search, install web search MCP, connect Parallel Search MCP, or make Search Before Building work → invoke `/setup-search-mcp` - User asks to monitor prod after shipping, post-deploy checks → invoke `/canary` - User asks to update docs after shipping → invoke `/document-release` - User asks to write docs from scratch, generate documentation, "document this feature/module" → invoke `/document-generate` diff --git a/docs/skills.md b/docs/skills.md index 8e8cb7adc..1b989ca78 100644 --- a/docs/skills.md +++ b/docs/skills.md @@ -44,6 +44,7 @@ Detailed guides for every gstack skill — philosophy, workflow, and examples. | **Multi-AI** | | | | [`/codex`](#codex) | **Second Opinion** | Independent review from OpenAI Codex CLI. Three modes: code review (pass/fail gate), adversarial challenge, and open consultation with session continuity. Cross-model analysis when both `/review` and `/codex` have run. | | [`/pair-agent`](#pair-agent) | **Remote Agent Bridge** | Pair a remote AI agent (OpenClaw, Codex, Cursor, Hermes) with your browser. Scoped tunnel, locked allowlist, session token. | +| [`/setup-search-mcp`](#setup-search-mcp) | **Search MCP Setup** | Free web search for agents. No account or API key by default. | | [`/setup-gbrain`](#setup-gbrain) | **Memory Sync** | Set up gbrain for cross-machine session memory sync. One command from zero to live. | | [`/sync-gbrain`](#sync-gbrain) | **Keep Brain Current** | Refresh gbrain against this repo's code; teach the agent when to use `gbrain search`/`code-def` over Grep. Idempotent; safe to re-run. | | | | | @@ -923,6 +924,25 @@ Claude: Imported 12 cookies for github.com from Comet. --- +## `/setup-search-mcp` + +This sets up free web search for agents through Parallel Search MCP. It gives +gstack's Search Before Building workflow a no-key path to public web search and +clean markdown from public URLs. + +``` +You: /setup-search-mcp + +Claude: Configured Parallel Search MCP for Claude Code. + Default setup is free and no-auth. + Restart Claude Code if the new MCP tools are not visible yet. +``` + +Use Search MCP for public web search. Use `/browse` for authenticated flows, +screenshots, clicks, visual QA, and stateful browser work. + +--- + ## `/autoplan` This is my **review autopilot mode**. diff --git a/gstack/llms.txt b/gstack/llms.txt index efe522f90..7de329b11 100644 --- a/gstack/llms.txt +++ b/gstack/llms.txt @@ -60,6 +60,7 @@ Conventions: - [/setup-browser-cookies](setup-browser-cookies/SKILL.md): Import cookies from your real Chromium browser into the headless browse session. - [/setup-deploy](setup-deploy/SKILL.md): Configure deployment settings for /land-and-deploy. - [/setup-gbrain](setup-gbrain/SKILL.md): Set up gbrain for this coding agent: install the CLI, initialize a local PGLite or Supabase brain, register MCP, capture per-remote trust policy. +- [/setup-search-mcp](setup-search-mcp/SKILL.md): Set up free web search for agents in gstack's Search Before Building workflow. - [/ship](ship/SKILL.md): Ship workflow: detect + merge base branch, run tests, review diff, bump VERSION, update CHANGELOG, commit, push, create PR. - [/skillify](skillify/SKILL.md): Codify the most recent successful /scrape flow into a permanent browser-skill on disk. - [/spec](spec/SKILL.md): Turn vague intent into a precise, executable spec in five phases. diff --git a/scripts/proactive-suggestions.json b/scripts/proactive-suggestions.json index d08c60853..40a4b4626 100644 --- a/scripts/proactive-suggestions.json +++ b/scripts/proactive-suggestions.json @@ -248,6 +248,11 @@ "routing": "One command from zero to \"gbrain is running, and this agent\ncan call it.\" Use when: \"setup gbrain\", \"connect gbrain\", \"start\ngbrain\", \"install gbrain\", \"configure gbrain for this machine\".", "voice_line": null }, + "setup-search-mcp": { + "lead": "Set up free web search for agents in gstack's Search Before Building workflow.", + "routing": "Adds Parallel Search MCP with no account or API key by default.\nUse when: \"setup search\", \"install search mcp\", \"connect Parallel Search MCP\",\n\"free web search\", \"agent web search\", \"make Search Before Building work\".", + "voice_line": null + }, "ship": { "lead": "Ship workflow: detect + merge base branch, run tests, review diff, bump VERSION, update CHANGELOG, commit, push, create PR.", "routing": "Use when asked to \"ship\", \"deploy\",\n\"push to main\", \"create a PR\", \"merge and push\", or \"get it deployed\".\nProactively invoke this skill (do NOT push/PR directly) when the user says code\nis ready, asks about deploying, wants to push code up, or asks to create a PR.", diff --git a/scripts/skill-check.ts b/scripts/skill-check.ts index 9182737ee..5e135aac5 100644 --- a/scripts/skill-check.ts +++ b/scripts/skill-check.ts @@ -13,9 +13,11 @@ import { discoverTemplates, discoverSkillFiles } from './discover-skills'; import * as fs from 'fs'; import * as path from 'path'; import { execSync } from 'child_process'; +import { ALL_HOST_CONFIGS, getExternalHosts, getHostConfig } from '../hosts/index'; const ROOT = path.resolve(import.meta.dir, '..'); const ROOT_REALPATH = fs.realpathSync(ROOT); +const CLAUDE_SKIPPED_SKILLS = new Set(getHostConfig('claude').generation.skipSkills ?? []); function isRepoRootSymlink(candidateDir: string): boolean { try { @@ -73,6 +75,11 @@ for (const { tmpl, output } of TEMPLATES) { continue; } if (!fs.existsSync(outPath)) { + const skillDir = path.dirname(tmpl); + if (CLAUDE_SKIPPED_SKILLS.has(skillDir)) { + console.log(` - ${output.padEnd(30)} — Claude-host generation skipped by host config`); + continue; + } hasErrors = true; console.log(` \u274c ${output.padEnd(30)} — generated file missing! Run: bun run gen:skill-docs`); continue; @@ -90,8 +97,6 @@ for (const file of SKILL_FILES) { // ─── External Host Skills (config-driven) ─────────────────── -import { getExternalHosts } from '../hosts/index'; - for (const hostConfig of getExternalHosts()) { const hostDir = path.join(ROOT, hostConfig.hostSubdir, 'skills'); if (fs.existsSync(hostDir)) { @@ -130,8 +135,6 @@ for (const hostConfig of getExternalHosts()) { // ─── Freshness (config-driven) ────────────────────────────── -import { ALL_HOST_CONFIGS } from '../hosts/index'; - for (const hostConfig of ALL_HOST_CONFIGS) { const hostFlag = hostConfig.name === 'claude' ? '' : ` --host ${hostConfig.name}`; console.log(`\n Freshness (${hostConfig.displayName}):`); diff --git a/setup-search-mcp/SKILL.md b/setup-search-mcp/SKILL.md new file mode 100644 index 000000000..c08481d04 --- /dev/null +++ b/setup-search-mcp/SKILL.md @@ -0,0 +1,612 @@ +--- +name: setup-search-mcp +preamble-tier: 1 +version: 1.0.0 +description: Set up free web search for agents in gstack's Search Before Building workflow. (gstack) +triggers: + - setup search + - install search mcp + - connect parallel search mcp + - free web search + - free search mcp + - agent web search + - search before building setup +allowed-tools: + - Bash + - AskUserQuestion +--- + + + + +## When to invoke this skill + +Adds Parallel Search MCP with no account or API key by default. +Use when: "setup search", "install search mcp", "connect Parallel Search MCP", +"free web search", "agent web search", "make Search Before Building work". + +## Preamble (run first) + +```bash +_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" || true +mkdir -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 -exec rm {} + 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" ;; esac +echo "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:-}" ]; }; then + echo "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) +fi +echo "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"; fi +echo "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" +mkdir -p ~/.gstack/analytics +if [ "$_TEL" != "off" ]; then +echo '{"skill":"setup-search-mcp","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 || true +fi +for _PF in $(find ~/.gstack/analytics -maxdepth 1 -name '.pending-*' 2>/dev/null); do + if [ -f "$_PF" ]; then + if [ "$_TEL" != "off" ] && [ -x "~/.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 || true + fi + rm -f "$_PF" 2>/dev/null || true + fi + break +done +eval "$(~/.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 || true + fi +else + echo "LEARNINGS: 0" +fi +~/.claude/skills/gstack/bin/gstack-timeline-log '{"skill":"setup-search-mcp","event":"started","branch":"'"$_BRANCH"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null & +_HAS_ROUTING="no" +if [ -f CLAUDE.md ] && grep -q "## Skill routing" CLAUDE.md 2>/dev/null; then + _HAS_ROUTING="yes" +fi +_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" ]; then + if [ -f ".claude/skills/gstack/VERSION" ] || [ -d ".claude/skills/gstack/.git" ]; then + _VENDORED="yes" + fi +fi +echo "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:-}" ]; then + export GSTACK_PLAN_MODE="active" +elif [ "${GSTACK_PLAN_MODE:-}" = "active" ]; then + export GSTACK_PLAN_MODE="active" +else + export GSTACK_PLAN_MODE="inactive" +fi +echo "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; 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 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 output shows `UPGRADE_AVAILABLE `: 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 `: 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`. + +Always run (regardless of choice): +```bash +rm -f ~/.gstack/.writing-style-prompt-pending +touch ~/.gstack/.writing-style-prompted +``` + +Skip if `WRITING_STYLE_PENDING` is `no`. + +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: + +```bash +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: +```bash +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: +```bash +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: +```bash +~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type first_task_scaffold_shown --skill "TASK_TOKEN" --outcome shown 2>/dev/null || true +touch ~/.gstack/.activated 2>/dev/null || true +``` + +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: + +```markdown + +## 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: +1. Run `git rm -r .claude/skills/gstack/` +2. Run `echo '.claude/skills/gstack/' >> .gitignore` +3. Run `~/.claude/skills/gstack/bin/gstack-team-init required` (or `optional`) +4. Run `git add .claude/ .gitignore CLAUDE.md && git commit -m "chore: migrate gstack from vendored to team mode"` +5. 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." + +Always run (regardless of choice): +```bash +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" 2>/dev/null || true +touch ~/.gstack/.vendoring-warned-${SLUG:-unknown} +``` + +If marker exists, skip. + +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) + +```bash +_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="~/.claude/skills/gstack/bin/gstack-brain-sync" +_BRAIN_CONFIG_BIN="~/.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" + fi + if [ -n "$_GBRAIN_PIN_PATH" ]; then + echo "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." + else + echo "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." + fi + fi +fi + +_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). +_GBRAIN_MCP_MODE="none" +if command -v jq >/dev/null 2>&1 && [ -f "$HOME/.claude.json" ]; then + _GBRAIN_MCP_TYPE=$(jq -r '.mcpServers.gbrain.type // .mcpServers.gbrain.transport // empty' "$HOME/.claude.json" 2>/dev/null) + case "$_GBRAIN_MCP_TYPE" in + url|http|sse) _GBRAIN_MCP_MODE="remote-http" ;; + stdio) _GBRAIN_MCP_MODE="local-stdio" ;; + esac +fi + +if [ -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" ]; then + echo "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)" + fi +fi + +if [ -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) + _BRAIN_AGE=$(( _BRAIN_NOW - _BRAIN_LAST )) + [ "$_BRAIN_AGE" -lt 86400 ] && _BRAIN_DO_PULL=0 + fi + if [ "$_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 ) || true + echo "$_BRAIN_NOW" > "$_BRAIN_LAST_PULL_FILE" + fi + "$_BRAIN_SYNC_BIN" --once 2>/dev/null || true +fi + +if [ "$_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=$(jq -r '.mcpServers.gbrain.url // empty' "$HOME/.claude.json" 2>/dev/null | sed -E 's|^https?://([^/:]+).*|\1|') + 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" +else + echo "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? + +Options: +- A) Everything allowlisted (recommended) +- B) Only artifacts +- C) Decline, keep everything local + +After answer: + +```bash +# Chosen mode: full | artifacts-only | off +"$_BRAIN_CONFIG_BIN" set artifacts_sync_mode +"$_BRAIN_CONFIG_BIN" set artifacts_sync_mode_prompted true +``` + +If A/B and `~/.gstack/.git` is missing, ask whether to run `gstack-artifacts-init`. Do not block the skill. + +At skill END before telemetry: + +```bash +"~/.claude/skills/gstack/bin/gstack-brain-sync" --discover-new 2>/dev/null || true +"~/.claude/skills/gstack/bin/gstack-brain-sync" --once 2>/dev/null || true +``` + + +## Model-Specific Behavioral Patch (claude) + +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: + +```bash +~/.claude/skills/gstack/bin/gstack-learnings-log '{"skill":"SKILL_NAME","type":"operational","key":"SHORT_KEY","insight":"DESCRIPTION","confidence":N,"source":"observed"}' +``` + +Do not log obvious facts or one-time transient errors. + +## Telemetry (run last) + +After workflow completion, log telemetry. Use skill `name:` from frontmatter. OUTCOME is success/error/abort/unknown. + +**PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to +`~/.gstack/analytics/`, matching preamble analytics writes. + +Run this bash: + +```bash +_TEL_END=$(date +%s) +_TEL_DUR=$(( _TEL_END - _TEL_START )) +rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true +# Session timeline: record skill completion (local-only, never sent anywhere) +~/.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 +# Local analytics (gated on telemetry setting) +if [ "$_TEL" != "off" ]; then +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 +fi +# Remote telemetry (opt-in, requires binary) +if [ "$_TEL" != "off" ] && [ -x ~/.claude/skills/gstack/bin/gstack-telemetry-log ]; then + ~/.claude/skills/gstack/bin/gstack-telemetry-log \ + --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \ + --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null & +fi +``` + +Replace `SKILL_NAME`, `OUTCOME`, and `USED_BROWSE` before running. + +## 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. + +# /setup-search-mcp — Free Web Search for Agents + +Set up Parallel Search MCP so agents working through Search Before Building get +free web search. The default setup is free and no-auth: no account, no API key, +no OAuth. + +This is not browser automation. Keep `/browse` and `/open-gstack-browser` for +authenticated pages, screenshots, clicks, visual QA, and stateful browser work. +Use Search MCP for public web search and clean markdown from public URLs. + +## User-invocable + +When the user types `/setup-search-mcp`, run this skill. + +## Rules + +- Prefer the current agent host. If this session is Claude Code, configure + Claude Code. If this session is Codex, configure Codex. +- Do not install into a different client just because its CLI exists. +- Do not edit private config files for unknown hosts. Print the manual MCP + values instead. +- Do not configure API-key auth or OAuth unless the user explicitly asks for + higher rate limits. If they do, use AskUserQuestion to ask whether they want + API-key auth or OAuth before printing or running auth-specific commands. + +## MCP Values + +- Server URL: `https://search.parallel.ai/mcp` +- Transport: Streamable HTTP +- Authentication: none by default +- Expected tools after restart: `web_search`, `web_fetch` +- OAuth URL, only if the user opts in: `https://search.parallel.ai/mcp-oauth` + +## Claude Code Setup + +Use this path only when the current agent host is Claude Code: + +```bash +claude mcp remove -s user "Parallel-Search-MCP" 2>/dev/null || true +claude mcp remove "Parallel-Search-MCP" 2>/dev/null || true +claude mcp add --scope user --transport http "Parallel-Search-MCP" https://search.parallel.ai/mcp +claude mcp list +``` + +Then tell the user to restart Claude Code if the new MCP tools are not visible +in the current session. After restart, Claude-style tool names usually appear as +`mcp__Parallel-Search-MCP__web_search` and +`mcp__Parallel-Search-MCP__web_fetch`. + +## Codex Setup + +Use this path only when the current agent host is Codex: + +```bash +codex mcp remove parallel-search 2>/dev/null || true +codex mcp add parallel-search --url https://search.parallel.ai/mcp +codex mcp list --json +``` + +Then tell the user to restart Codex if the new MCP tools are not visible in the +current session. + +## Manual Setup + +For any other MCP-capable host, do not guess at the config file. Give the user +the MCP values above and ask them to add the server through that host's normal +MCP settings. Tell them the host may need a restart before `web_search` and +`web_fetch` appear. + +## Report + +After setup, report: + +- Which host path you used. +- That the default setup is free and no-auth. +- Whether the host command listed the server. +- Whether the current agent session must be restarted before the new tools are + available. diff --git a/setup-search-mcp/SKILL.md.tmpl b/setup-search-mcp/SKILL.md.tmpl new file mode 100644 index 000000000..dbf75d0c8 --- /dev/null +++ b/setup-search-mcp/SKILL.md.tmpl @@ -0,0 +1,102 @@ +--- +name: setup-search-mcp +preamble-tier: 1 +version: 1.0.0 +description: | + Set up free web search for agents in gstack's Search Before Building workflow. + Adds Parallel Search MCP with no account or API key by default. + Use when: "setup search", "install search mcp", "connect Parallel Search MCP", + "free web search", "agent web search", "make Search Before Building work". (gstack) +triggers: + - setup search + - install search mcp + - connect parallel search mcp + - free web search + - free search mcp + - agent web search + - search before building setup +allowed-tools: + - Bash + - AskUserQuestion +--- + +{{PREAMBLE}} + +# /setup-search-mcp — Free Web Search for Agents + +Set up Parallel Search MCP so agents working through Search Before Building get +free web search. The default setup is free and no-auth: no account, no API key, +no OAuth. + +This is not browser automation. Keep `/browse` and `/open-gstack-browser` for +authenticated pages, screenshots, clicks, visual QA, and stateful browser work. +Use Search MCP for public web search and clean markdown from public URLs. + +## User-invocable + +When the user types `/setup-search-mcp`, run this skill. + +## Rules + +- Prefer the current agent host. If this session is Claude Code, configure + Claude Code. If this session is Codex, configure Codex. +- Do not install into a different client just because its CLI exists. +- Do not edit private config files for unknown hosts. Print the manual MCP + values instead. +- Do not configure API-key auth or OAuth unless the user explicitly asks for + higher rate limits. If they do, use AskUserQuestion to ask whether they want + API-key auth or OAuth before printing or running auth-specific commands. + +## MCP Values + +- Server URL: `https://search.parallel.ai/mcp` +- Transport: Streamable HTTP +- Authentication: none by default +- Expected tools after restart: `web_search`, `web_fetch` +- OAuth URL, only if the user opts in: `https://search.parallel.ai/mcp-oauth` + +## Claude Code Setup + +Use this path only when the current agent host is Claude Code: + +```bash +claude mcp remove -s user "Parallel-Search-MCP" 2>/dev/null || true +claude mcp remove "Parallel-Search-MCP" 2>/dev/null || true +claude mcp add --scope user --transport http "Parallel-Search-MCP" https://search.parallel.ai/mcp +claude mcp list +``` + +Then tell the user to restart Claude Code if the new MCP tools are not visible +in the current session. After restart, Claude-style tool names usually appear as +`mcp__Parallel-Search-MCP__web_search` and +`mcp__Parallel-Search-MCP__web_fetch`. + +## Codex Setup + +Use this path only when the current agent host is Codex: + +```bash +codex mcp remove parallel-search 2>/dev/null || true +codex mcp add parallel-search --url https://search.parallel.ai/mcp +codex mcp list --json +``` + +Then tell the user to restart Codex if the new MCP tools are not visible in the +current session. + +## Manual Setup + +For any other MCP-capable host, do not guess at the config file. Give the user +the MCP values above and ask them to add the server through that host's normal +MCP settings. Tell them the host may need a restart before `web_search` and +`web_fetch` appear. + +## Report + +After setup, report: + +- Which host path you used. +- That the default setup is free and no-auth. +- Whether the host command listed the server. +- Whether the current agent session must be restarted before the new tools are + available. diff --git a/test/setup-search-mcp-structure.test.ts b/test/setup-search-mcp-structure.test.ts new file mode 100644 index 000000000..da080e815 --- /dev/null +++ b/test/setup-search-mcp-structure.test.ts @@ -0,0 +1,41 @@ +import { describe, test, expect } from 'bun:test'; +import * as fs from 'fs'; +import * as path from 'path'; + +const ROOT = path.resolve(import.meta.dir, '..'); +const TMPL = fs.readFileSync(path.join(ROOT, 'setup-search-mcp', 'SKILL.md.tmpl'), 'utf-8'); + +describe('setup-search-mcp structural contract', () => { + test('defaults to free no-auth setup', () => { + expect(TMPL).toContain('free web search for agents'); + expect(TMPL).toContain('no account, no API key'); + expect(TMPL).toContain('no OAuth'); + expect(TMPL).toContain('Authentication: none by default'); + expect(TMPL).not.toContain('Authorization: Bearer'); + }); + + test('uses exact supported host commands', () => { + expect(TMPL).toContain('claude mcp add --scope user --transport http "Parallel-Search-MCP" https://search.parallel.ai/mcp'); + expect(TMPL).toContain('codex mcp add parallel-search --url https://search.parallel.ai/mcp'); + expect(TMPL).toContain('claude mcp list'); + expect(TMPL).toContain('codex mcp list --json'); + }); + + test('does not guess unknown host config files', () => { + expect(TMPL).toContain('Do not install into a different client just because its CLI exists'); + expect(TMPL).toContain('do not guess at the config file'); + expect(TMPL).toContain('Expected tools after restart: `web_search`, `web_fetch`'); + }); + + test('keeps auth and browser automation boundaries explicit', () => { + expect(TMPL).toContain('AskUserQuestion'); + expect(TMPL).toContain('API-key auth or OAuth'); + expect(TMPL).toContain('This is not browser automation'); + expect(TMPL).toContain('/browse'); + expect(TMPL).toContain('/open-gstack-browser'); + }); + + test('does not depend on the removed verifier helper', () => { + expect(TMPL).not.toContain('gstack-search-mcp-verify'); + }); +}); diff --git a/test/skill-coverage-matrix.ts b/test/skill-coverage-matrix.ts index 7359afbce..fc38a5f2a 100644 --- a/test/skill-coverage-matrix.ts +++ b/test/skill-coverage-matrix.ts @@ -159,6 +159,11 @@ export const SKILL_COVERAGE: Record = { 'context-restore': { gate: ['test/skill-e2e-context-skills.test.ts', 'test/skill-coverage-floor.test.ts'], periodic: [] }, 'setup-deploy': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] }, 'setup-browser-cookies': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] }, + 'setup-search-mcp': { + gate: ['test/setup-search-mcp-structure.test.ts', 'test/skill-coverage-floor.test.ts'], + periodic: [], + rationale: 'Search MCP setup has deterministic structural coverage for no-auth defaults, supported host commands, and manual-host guidance.', + }, 'setup-gbrain': { gate: [ 'test/skill-e2e-setup-gbrain-bad-token.test.ts',