Files
gstack/skills/plan/references/legacy/sync-gbrain.md
T
Sinabina d6ef673e4d feat: add provider-aware browser QA setup
Detect host-native browser tools before offering the isolated local Chromium fallback, add a common readiness fixture, harden managed browser startup, and verify standards installs expose one canonical QA skill.
2026-07-20 16:01:24 -07:00

24 KiB

Host-neutral runtime bindings

These assignments select stable paths only; they do not install anything or grant consent:

GSTACK_HOME="${GSTACK_HOME:-$HOME/.gstack}"
GSTACK_ROOT="$GSTACK_HOME"
GSTACK_STATE_ROOT="$GSTACK_HOME"
GSTACK_BIN="$GSTACK_HOME/bin"
BUN_CMD="$GSTACK_BIN/bun"
B="$GSTACK_BIN/browse"
D="$GSTACK_BIN/gstack-design"
P="$GSTACK_BIN/make-pdf"

$plan --mode Discovery --module sync-gbrain — Keep gbrain current and teach the agent to use it

You are running the canonical "keep this brain up to date" verb. $plan --mode Discovery --module setup-gbrain installs gbrain once; $plan --mode Discovery --module sync-gbrain runs every time the user wants the brain refreshed against this repo's current state, and refreshes the agent-side guidance in CLAUDE.md so the coding agent knows when to prefer gbrain search over Grep.

Architecture (post-codex review): This skill uses gbrain v0.20.0+'s native code surfaces (gbrain sources add, gbrain sync --strategy code, gbrain reindex-code, gbrain code-def/code-refs/code-callers/code-callees). It does NOT use gbrain import (that path is for markdown directories). It does NOT touch "${GSTACK_HOME:-$HOME/.gstack}"/ indexing (the existing gstack-gbrain-source-wireup owns that — never double-store).

User-invocable

When the user types $plan --mode Discovery --module sync-gbrain, run this skill. Argument modes (parsed by the skill itself, not a dispatcher binary):

  • $plan --mode Discovery --module sync-gbrain — incremental sync (default; mtime fast-path; ~50ms steady-state)
  • $plan --mode Discovery --module sync-gbrain --full — full code reindex via gbrain reindex-code (~25-35 min on a big repo). Auto-builds the call graph (gbrain dream) only when it was never built.
  • $plan --mode Discovery --module sync-gbrain --dream — build this source's call graph (gbrain code-callers/code-callees) via a source-scoped gbrain dream --source <id> cycle; ~minutes; runs lock-free after the sync stages. Always forces, even if already built. Only produces a graph on a code-aware schema pack; otherwise the run reports a WARN explaining why the graph is still empty.
  • $plan --mode Discovery --module sync-gbrain --no-dream — skip the dream cycle that --full would otherwise auto-run.
  • $plan --mode Discovery --module sync-gbrain --code-only — only run the code stage; skip memory + brain-sync
  • $plan --mode Discovery --module sync-gbrain --dry-run — preview what would sync; no writes anywhere
  • $plan --mode Discovery --module sync-gbrain --no-memory / --no-brain-sync — selectively skip stages
  • $plan --mode Discovery --module sync-gbrain --quiet — suppress per-stage output
  • $plan --mode Discovery --module sync-gbrain --refresh-cache — force-rebuild brain-aware planning cache (v1.48; replaces /brain-refresh-context per D1 fold). Skips code + memory stages; routes to gstack-brain-cache refresh --project <slug>.
  • $plan --mode Discovery --module sync-gbrain --audit — emit summary of gstack-owned pages per project + sensitive-content audit (v1.48 / D10 lifecycle). Read-only.

Pass-through args go straight to the orchestrator at $GSTACK_BIN/gstack-gbrain-sync.ts.

--refresh-cache short-circuit: when this flag is present, the skill runs ONLY the cache refresh (gstack-brain-cache refresh --project <slug> for the current worktree's slug, plus a cross-project refresh of user-profile if gstack/user-profile/<user-slug> exists). Code + memory + brain-sync stages are skipped. Useful when the user knows the brain has new info gstack should pick up before the next planning skill.

--audit short-circuit: when this flag is present, the skill runs gstack-brain-cache list --project <slug> --json, summarizes by page type, then scans for any cached salience entries that ended up outside the SALIENCE_DEFAULT_ALLOWLIST (T17 / D9 leak check). Read-only; no modifications to brain or cache.


Step 1: State probe

Before doing anything, check that $plan --mode Discovery --module setup-gbrain has been run on this Mac.

$GSTACK_BIN/gstack-gbrain-detect 2>/dev/null

Brain trust policy gate (v1.48 / Phase 1.5 / D4 — added by T13+T5c): If gbrain_mcp_mode == "remote-http" from the detect output AND the per- endpoint policy is unset, the policy question MUST fire here before the orchestrator runs. Local engines auto-set to personal silently per the per-transport default table.

_HASH=$($GSTACK_BIN/gstack-config endpoint-hash 2>/dev/null)
_POLICY=$($GSTACK_BIN/gstack-config get brain_trust_policy@$_HASH 2>/dev/null || echo unset)
echo "BRAIN_TRUST_POLICY[$_HASH]: $_POLICY"

If _POLICY == "unset" AND _HASH != "local", AskUserQuestion per the Step 9.5 wording in $plan --mode Discovery --module setup-gbrain (personal vs shared, with persistence to brain_trust_policy@<hash> and conditional artifacts_sync_mode=full flip for personal). Then continue.

If _POLICY == "unset" AND _HASH == "local", auto-set personal:

$GSTACK_BIN/gstack-config set brain_trust_policy@$_HASH personal

Split-engine model (v1.34.0.0+). Code stage runs locally against the per-machine gbrain engine (PGLite or whatever gbrain config points to), with each worktree of a repo registered as its own source. Memory stage also runs locally in local-stdio MCP mode — gstack-memory-ingest shells out to gbrain import against the same local engine. In remote-http MCP mode (Path 4), the memory stage instead persists staged markdown to "${GSTACK_HOME:-$HOME/.gstack}"/transcripts/<run-id>/ and the artifacts pipeline pushes it to the brain admin's pull job (plan D11). Brain-sync (the gstack-brain-sync push to git) is the one stage that never touches local engine and runs regardless of mode.

Practically: local PGLite stays code-only on remote-http machines; the remote brain holds everything else. Local-stdio machines mix code + transcripts in one local engine, as they always have.

Also check the per-repo trust policy. If gstack-gbrain-repo-policy get for this repo returns deny, STOP:

"This repo's gbrain trust policy is deny. Run $plan --mode Discovery --module setup-gbrain --repo to change it before syncing."


Step 1.5: Local engine pre-flight (plan D12)

Read gbrain_local_status from the Step 1 detect output. Branch as follows BEFORE invoking the orchestrator:

  • ok: proceed to Step 2 normally.
  • timeout: proceed to Step 2 — the engine is most likely healthy but slow (cold pooler connection, #1964). Tell the user in one line: "Engine probe timed out (>15s) — proceeding; raise GSTACK_GBRAIN_PROBE_TIMEOUT_MS if your pooler is slow." Do NOT treat this as a broken config.
  • no-cli: STOP. "Local gbrain CLI not installed. Run $plan --mode Discovery --module setup-gbrain first."
  • missing-config AND gbrain_mcp_mode == "remote-http": tell the user "Your brain queries (the mcp__gbrain__* tools) work via remote MCP, but symbol code search needs a local PGLite. Run $plan --mode Discovery --module setup-gbrain and pick 'Yes' at the new 'local code index' prompt (Step 4.5), or run gbrain init --pglite --json --embedding-model voyage:voyage-code-3 --embedding-dimensions 1024 directly (drop the voyage flags if VOYAGE_API_KEY isn't set). Continuing without code stage." Then proceed to Step 2 — the orchestrator's runCodeImport() and runMemoryIngest() will return SKIP per plan D12; only runBrainSyncPush() will run. Do NOT abort.
  • missing-config AND gbrain_mcp_mode != "remote-http": STOP. "Local gbrain CLI is installed but no engine config. Run $plan --mode Discovery --module setup-gbrain first."
  • broken-config OR broken-db: STOP with a clear message:
    Local gbrain config at ~/.gbrain/config.json points at an unreachable
    engine (status: {gbrain_local_status}). Two options:
      1. Re-run $plan --mode Discovery --module setup-gbrain — Step 1.5 offers Retry / Switch to PGLite /
         Switch brain mode / Quit (plan D4).
      2. Repair manually: mv ~/.gbrain/config.json ~/.gbrain/config.json.bak
         && gbrain init --pglite --json --embedding-model voyage:voyage-code-3 \
            --embedding-dimensions 1024   (drop voyage flags if VOYAGE_API_KEY unset)
    Re-run $plan --mode Discovery --module sync-gbrain after.
    
    Do NOT continue — the orchestrator would skip code+memory and only run brain-sync, which is a degraded state the user should fix explicitly.

This pre-flight short-circuits the orchestrator before it spends ~80ms probing the engine again. The orchestrator independently runs the same classifier for defense-in-depth, but Step 1.5's STOP is where the user gets the actionable remediation message.


Step 2: Run the orchestrator

Pass user args to the orchestrator. Do not paraphrase them — pass through as-is.

$GSTACK_BIN/gstack-gbrain-sync <user-args>

The orchestrator runs three stages: code → memory → brain-sync (per the plan's storage tiering). Each stage failure is non-fatal; subsequent stages still run. State is persisted to "${GSTACK_HOME:-$HOME/.gstack}"/.gbrain-sync-state.json via tmp-file + atomic rename. Concurrent runs are blocked by a lock file at "${GSTACK_HOME:-$HOME/.gstack}"/.sync-gbrain.lock (5-min stale-takeover).


Step 3: Code-index health check

After the sync run, query gbrain for the cwd source's page_count:

SOURCE_ID=$(grep -o '"source_id":"[^"]*"' "${GSTACK_HOME:-$HOME/.gstack}"/.gbrain-sync-state.json 2>/dev/null \
  | head -1 | sed 's/.*"source_id":"//;s/".*//')
PAGES=$(gbrain sources list --json 2>/dev/null \
  | jq -r --arg id "$SOURCE_ID" '.sources[] | select(.id==$id) | .page_count' 2>/dev/null \
  || echo 0)
echo "cwd source: $SOURCE_ID, page_count: $PAGES"

If PAGES is 0 or empty AND the user did NOT pass --no-code AND mode was not --full, AskUserQuestion via the format in the preamble:

D1 — This repo has 0 indexed pages in gbrain. Run a full code reindex now?

ELI10: gbrain hasn't indexed this repo's code yet. The semantic search tools (gbrain search, code-def, code-refs) will return nothing until we run a full pass. Takes ~25-35 minutes on a big Mac.

Recommendation: A — the brain is unusable for code search until indexed, and Step 2 of this skill already verified gbrain is configured correctly.

Note: options differ in kind, not coverage — no completeness score.

A) Run $plan --mode Discovery --module sync-gbrain --full now (recommended) B) Skip — I'll run it later

If A: re-invoke the orchestrator with --full --code-only. If B: continue to Step 4 with the empty-corpus state recorded.


Step 3.5: Call-graph health check (offer --dream)

gbrain code-callers / code-callees (who-calls-this / what-this-calls) return count: 0 until a gbrain dream cycle runs the resolve_symbol_edges phase for this source — not done by the code import in Step 2.

One hard prerequisite: building a call graph requires this source's active schema pack to extract code symbols (the extract_atoms phase). On a pack that doesn't declare it (e.g. gbrain-base / gbrain-base-v2), a dream cycle completes but resolve_symbol_edges matches nothing — the graph stays empty no matter how many times you run it. So "build the call graph" is only meaningful on a code-aware pack. The --dream stage detects this and reports it honestly (a WARN row) rather than claiming a build that didn't happen. gbrain exposes pack capability only at cycle runtime (no pre-flight query as of 0.41.x), so we can't detect it before running. code-def / code-refs need the same symbol extraction; they are NOT free "direct lookups" on a non-code-aware pack.

Detect whether this source's call graph is built via doctor's cycle_freshness check, matching the cwd SOURCE_ID literally:

SOURCE_ID=$(grep -o '"source_id":"[^"]*"' "${GSTACK_HOME:-$HOME/.gstack}"/.gbrain-sync-state.json 2>/dev/null \
  | head -1 | sed 's/.*"source_id":"//;s/".*//')
CYCLE=$(gbrain doctor --json --fast 2>/dev/null \
  | jq -r --arg id "$SOURCE_ID" '
      (.checks[] | select(.name=="cycle_freshness")) as $c
      | if $c.status=="ok" then "completed"
        elif ($c.message | index($id)) then "never"
        else "unknown" end' 2>/dev/null || echo unknown)
# index($id) = literal substring (NOT test() regex), matching the lib reader in
# cycleCompleted(). A fail/warn that doesn't name this source → "unknown" (don't
# mask other-source failures).
echo "call graph for $SOURCE_ID: $CYCLE"

If CYCLE == never AND the user did NOT pass --dream/--full AND Step 3 PAGES > 0, AskUserQuestion via the format in the preamble:

D2 — This repo's call graph isn't built. Build it now?

ELI10: gbrain code-callers/code-callees (who calls this function / what it calls) return nothing until the resolve_symbol_edges phase runs for this source. gbrain dream --source <this source> runs it (scoped to this worktree's code, takes a few minutes). It only produces a graph if this source's schema pack extracts code symbols; if it doesn't, the run completes but the graph stays empty and the dream row will say so.

Recommendation: A — call-graph queries return 0 until this runs, and the code index is already populated. If A comes back as a WARN ("pack does not extract code symbols"), the fix is a code-aware schema pack, not re-running dream.

Note: options differ in kind, not coverage — no completeness score.

A) Run $plan --mode Discovery --module sync-gbrain --dream now (recommended) B) Skip — I'll run it later

If A: re-invoke the orchestrator with --dream --code-only (skips memory + brain-sync; the dream stage still runs because it's gated on --dream). Then report the dream stage's ACTUAL row — OK call graph built (N edges) vs a WARN that names why the graph is still empty (non-code-aware pack, missing embedding key, or 0 edges matched). Do not claim success on a WARN. If B: continue to Step 4 with the call-graph-not-built state recorded for the verdict.

If CYCLE == completed or unknown, do not prompt — but note completed means only that a cycle has run, not that edges exist (a non-code-aware pack reports completed with an empty graph). Step 5's verdict row surfaces the real state.


Step 4: Refresh ## GBrain Search Guidance block in CLAUDE.md

Capability check (per $plan --mode Engineering --module plan-eng-review §6):

SLUG="_capability_check_$$"
CAPABILITY_OK=0
if [ -f ~/.gbrain/config.json ] && \
   gbrain --version 2>/dev/null | grep -q '^gbrain '; then
  # Do NOT export GBRAIN_PREPARE here (#1965). gbrain auto-disables prepared
  # statements on transaction-mode poolers (port 6543) — forcing them on
  # breaks every write with "prepared statement does not exist". Users on a
  # session-mode pooler at 6543 can set GBRAIN_PREPARE=true themselves (the
  # gbrain banner documents this override).
  if echo "ping" | gbrain put "$SLUG" >/dev/null 2>&1; then
    # Retry search up to 3 times with 1s delay — under transaction-mode
    # pooling the search index may not be visible on the next connection
    # immediately after the put.
    for _attempt in 1 2 3; do
      if gbrain search "ping" 2>/dev/null | grep -q "$SLUG"; then
        CAPABILITY_OK=1
        break
      fi
      sleep 1
    done
  fi
fi
gbrain delete "$SLUG" 2>/dev/null || true

Then update CLAUDE.md based on capability state:

If CAPABILITY_OK=1 — write or update the block. Idempotent: find the HTML-comment-delimited block; replace its body if it exists; append at the end of CLAUDE.md if it doesn't. NEVER duplicate. Block is machine-AGNOSTIC (no engine, no page counts, no last-sync time — those are in the existing ## GBrain Configuration block).

Verbatim block content (copy exactly):

## GBrain Search Guidance (configured by $plan --mode Discovery --module sync-gbrain)
<!-- gstack-gbrain-search-guidance:start -->

GBrain is set up and synced on this machine. The agent should prefer gbrain
over Grep when the question is semantic or when you don't know the exact
identifier yet.

**This worktree is pinned to a worktree-scoped code source** via the
`.gbrain-source` file in the repo root (kubectl-style context).
`gbrain code-def`, `code-refs`, `code-callers`, `code-callees`, `search`, and
`query` from anywhere under this worktree route to that source by default —
no `--source` flag needed (gbrain >= 0.41.38.0; on older gbrain the call-graph
commands need `--source "$(cat .gbrain-source)"`). Conductor sibling worktrees
of the same repo each have their own pin and their own indexed pages, so
semantic results match the code on disk here.

Call-graph queries (`code-callers`/`code-callees`) also need the graph to be
built first — run `$plan --mode Discovery --module sync-gbrain --dream` (or `--full`) if they return
`count: 0`. This only works if this source's gbrain schema pack extracts code
symbols; on a non-code-aware pack `--dream` completes but the graph stays empty
and reports a WARN. `code-def`/`code-refs` need the same extraction.

Two indexed corpora available via the `gbrain` CLI:
- This worktree's code (auto-pinned via `.gbrain-source`).
- `"${GSTACK_HOME:-$HOME/.gstack}"/` curated memory (registered as `gstack-brain-<user>` source via
  the existing federation pipeline).

Prefer gbrain when:
- "Where is X handled?" / semantic intent, no exact string yet:
    `gbrain search "<terms>"` or `gbrain query "<question>"`
- "Where is symbol Y defined?" / symbol-based code questions:
    `gbrain code-def <symbol>` or `gbrain code-refs <symbol>`
- "What calls Y?" / "What does Y depend on?":
    `gbrain code-callers <symbol>` / `gbrain code-callees <symbol>`
- "What did we decide last time?" / past plans, retros, learnings:
    `gbrain search "<terms>" --source gstack-brain-<user>`

Grep is still right for known exact strings, regex, multiline patterns, and
file globs. Run `$plan --mode Discovery --module sync-gbrain` after meaningful code changes; for ongoing
auto-sync across all worktrees, run `gbrain autopilot --install` once per
machine — gbrain's daemon handles incremental refresh on a schedule.

Safety: don't run `$plan --mode Discovery --module sync-gbrain` while `gbrain autopilot` is active — the
orchestrator refuses destructive source ops when it detects a running autopilot
to avoid racing it (#1734). Prefer registering user repos with `gbrain sources
add --path <dir>` (no `--url`): URL-managed sources can auto-reclone, and the
sync code walk for them requires an explicit `--allow-reclone` opt-in.

<!-- gstack-gbrain-search-guidance:end -->

Use the Read + Edit tools. The find-and-replace target is the entire region from <!-- gstack-gbrain-search-guidance:start --> through <!-- gstack-gbrain-search-guidance:end -->. If those markers are missing, search for ## GBrain Search Guidance (configured by $plan --mode Discovery --module sync-gbrain) heading and replace from there to the next ## or EOF. If no heading exists, append the entire block at the end of CLAUDE.md.

Atomic write: write the new CLAUDE.md content to a tmp file alongside it (e.g., CLAUDE.md.sync-gbrain.tmp) then mv to atomic-rename, so a crash mid-write never leaves the file half-modified.

If CAPABILITY_OK=0 — REMOVE the block entirely if present. Use the same Edit tool to strip the start/end-marker region. The ## GBrain Configuration block stays in place (it's a record of the install, not a capability claim).

Do NOT crash if CLAUDE.md is missing or unwritable — log a warning and continue.


Step 5: Verdict block (idempotent doctor output)

Print a status block matching $plan --mode Discovery --module setup-gbrain Step 10 conventions. Each row is [OK]/[FIX]/[WARN]/[ERR]. Reuse gbrain doctor --json --fast for informational rows but DO NOT gate the guidance block on doctor (per $plan --mode Engineering --module plan-eng-review §6 — doctor is too strict for unrelated reasons).

gbrain status: GREEN

  CLI ............. OK   <gbrain version>
  Engine .......... OK   <pglite|supabase>
  Capability ...... OK   write+search round-trip
  CWD source ...... OK   <gstack-code-{repo_slug}> (page_count=<N>)
  Call graph ...... OK   <N> edges resolved (code-callers/callees live)
  "${GSTACK_HOME:-$HOME/.gstack}" source. OK   <gstack-brain-{user}> (page_count=<N>) — managed by $plan --mode Discovery --module setup-gbrain
  Memory sync ..... OK   <artifacts_sync_mode>
  CLAUDE.md ....... OK   ## GBrain Search Guidance present
  Last sync ....... OK   <last_sync from state file>

Run `$plan --mode Discovery --module sync-gbrain` again any time gbrain feels off; safe and idempotent.

The Call graph row reports the most authoritative signal available:

  1. If a dream stage ran this invocation (--dream, or --full auto-build), mirror its row verbatim — it's the ground truth for this run:
    • OK <N> edges resolved (code-callers/callees live)
    • WARN dream ran but this source's schema pack does not extract code symbols — switch to a code-aware pack (\gbrain schema use `)`
    • WARN dream ran but the embed phase failed (missing embedding key)
    • WARN dream ran but resolved 0 edges (no code symbols matched yet)
  2. Otherwise fall back to the CYCLE value from Step 3.5, with honest wording (a completed cycle proves a cycle ran, NOT that edges exist):
    • completedOK cycle complete — code-callers/callees live IF this source's pack extracts code symbols
    • neverWARN call graph not built — run $plan --mode Discovery --module sync-gbrain --dream
    • unknownWARN could not probe call graph (doctor unavailable) — run $plan --mode Discovery --module sync-gbrain --dream if code-callers returns 0

Any WARN Call graph row flips the verdict to YELLOW.

If any row is YELLOW or RED, the verdict line says so and the failing rows surface a one-line "next action" (e.g., Capability ...... ERR capability check failed; CLAUDE.md guidance block REMOVED — run $plan --mode Discovery --module setup-gbrain to repair). A never/unknown Call graph row flips the verdict to YELLOW.


Concurrency note

This skill is safe to run concurrently from multiple terminals on the same Mac. The orchestrator acquires a lock at "${GSTACK_HOME:-$HOME/.gstack}"/.sync-gbrain.lock before any state-file or CLAUDE.md mutation and exits with code 2 if another sync is in flight. Stale locks (process died) auto-clear after 5 minutes.

Cross-machine note

The ## GBrain Search Guidance block is committed to the repo's CLAUDE.md and travels with git push/git pull — NOT through "${GSTACK_HOME:-$HOME/.gstack}"/.brain-allowlist (which is for "${GSTACK_HOME:-$HOME/.gstack}"/ brain-sync only). On a different Mac with a synced CLAUDE.md but no local gbrain, $plan --mode Discovery --module sync-gbrain detects the mismatch via the capability check and REMOVES the block (the local agent shouldn't be told to use a tool that isn't installed).

Status reporting

End with a Completion Status (per the preamble protocol):

  • DONE — all stages green, CLAUDE.md guidance block present, verdict GREEN.
  • DONE_WITH_CONCERNS — sync ran but at least one stage failed or capability check failed. List which.
  • BLOCKED — could not acquire lock, gbrain not on PATH, or per-repo policy is deny. State the blocker.
  • NEEDS_CONTEXT — $plan --mode Discovery --module setup-gbrain has not been run, or gbrain doctor shows a state that requires user decision (e.g., engine migration).

Upstream judgment port: PR #679

Match the user language

User-language rule

Write questions, progress updates, reports, and artifacts in the language used by the user. Source material, code identifiers, commands, and quotations may remain in their original language when translating them would reduce accuracy.