Files
gstack/setup-gbrain/sections/brain-init.md.tmpl
T
garrytan 26c6bf263f setup-gbrain, sync-gbrain: fix stale facts and strip plan archaeology
Applies s09 H1a, H1c (Mac-only wording; the installer supports Linux and
Windows), H2 (smoke test has no delete step), H3 (five invocation modes),
H4 (no CI grep test backs the telemetry claim), H7 (Step 4.5 does not exist;
the prompt is Path 4 step 4d), M11, M12, M13, M15, M18, M19 (plan codes,
issue numbers, version pins, rename story), M14 (restore-from-sync never
shipped), M16 (draft self-dialogue in the Supabase steps), M17 (passed
sunset date, manual merge into both sections).

W7a: retires the setup-gbrain-bin-invocation-paths 'now persists staged
transcripts' change-detector (t06 #17); the no-bare-invocation regex tests
keep the contract.
2026-10-03 00:08:46 +00:00

268 lines
11 KiB
Cheetah

Path-specific. Run ONLY the sub-section below for the path picked in Step 2
(or the Switch flow when Step 2 chose engine migration).
### Path 1 (Supabase, existing URL)
Source the secret-read helper, collect URL with `read -s` + redacted preview:
```bash
. ~/.claude/skills/gstack/bin/gstack-gbrain-lib.sh
read_secret_to_env GBRAIN_POOLER_URL "Paste Session Pooler URL: " \
--echo-redacted 's#://[^@]*@#://***@#'
```
Then validate structurally:
```bash
printf '%s' "$GBRAIN_POOLER_URL" | ~/.claude/skills/gstack/bin/gstack-gbrain-supabase-verify -
```
If the verify exit code is 3 (direct-connection URL), the verifier's own
message explains the fix; surface it and re-prompt for a Session Pooler URL.
On success, hand off to gbrain via env var (never argv):
```bash
GBRAIN_DATABASE_URL="$GBRAIN_POOLER_URL" gbrain init --non-interactive --json
```
Then `unset GBRAIN_POOLER_URL GBRAIN_DATABASE_URL` immediately. The URL is
now persisted in `~/.gbrain/config.json` at mode 0600 by gbrain itself.
### Path 2a (Supabase, auto-provision)
Show this PAT scope disclosure verbatim BEFORE collecting the token:
> *This Supabase Personal Access Token grants full read/write/delete access
> to every project in your Supabase account, not just the `gbrain` one we're
> about to create. Supabase doesn't currently support scoped tokens. We use
> this PAT only to: create one project, poll it until healthy, read the
> Session Pooler URL — then discard it from process memory. The token
> remains valid on Supabase's side until you manually revoke it at
> https://supabase.com/dashboard/account/tokens — we recommend revoking
> immediately after setup completes.*
Then:
```bash
. ~/.claude/skills/gstack/bin/gstack-gbrain-lib.sh
read_secret_to_env SUPABASE_ACCESS_TOKEN "Paste PAT: "
```
Ask the tier question via AskUserQuestion: "Which Supabase tier?" Present
Free (2-project limit, pauses after 7d inactivity) vs Pro ($25/mo, no
pauses, recommended for real use). Explain that tier is **org-level** (per
the Management API contract) — user picks their org based on its current
tier. Pro may require them to upgrade the org first at supabase.com.
List orgs, pick one (AskUserQuestion if multiple):
```bash
orgs=$(~/.claude/skills/gstack/bin/gstack-gbrain-supabase-provision list-orgs --json)
```
If the `.orgs` array is empty, surface: "Your Supabase account has no
organizations. Create one at https://supabase.com/dashboard, then re-run
`/setup-gbrain`." STOP.
Ask the user for a region (default `us-east-1`; valid values are the 18
enum values in the Supabase Management API — list a few common ones, let
them pick "Other" for a full list).
Generate the DB password (never shown to the user):
```bash
export DB_PASS=$(openssl rand -base64 24)
```
Set up a SIGINT trap so an interrupted provision can be resumed or deleted:
```bash
trap 'echo ""; echo "gstack-gbrain: interrupted. In-flight ref: $INFLIGHT_REF"; \
echo "Resume: /setup-gbrain --resume-provision $INFLIGHT_REF"; \
echo "Delete: https://supabase.com/dashboard/project/$INFLIGHT_REF"; \
unset SUPABASE_ACCESS_TOKEN DB_PASS; exit 130' INT TERM
```
Create + wait + fetch:
```bash
result=$(~/.claude/skills/gstack/bin/gstack-gbrain-supabase-provision \
create gbrain "$REGION" "$ORG_SLUG" --json)
INFLIGHT_REF=$(echo "$result" | jq -r .ref)
~/.claude/skills/gstack/bin/gstack-gbrain-supabase-provision wait "$INFLIGHT_REF" --json
pooler=$(~/.claude/skills/gstack/bin/gstack-gbrain-supabase-provision \
pooler-url "$INFLIGHT_REF" --json)
GBRAIN_DATABASE_URL=$(echo "$pooler" | jq -r .pooler_url)
export GBRAIN_DATABASE_URL
gbrain init --non-interactive --json
unset SUPABASE_ACCESS_TOKEN DB_PASS GBRAIN_DATABASE_URL INFLIGHT_REF
trap - INT TERM
```
After success, emit the PAT revocation reminder:
> "Setup complete. Revoke the PAT you pasted at
> https://supabase.com/dashboard/account/tokens — we've already discarded
> it from memory and don't need it again. The gbrain project will continue
> working because it uses its own embedded database password."
### Path 2b (Supabase, manual)
Walk the user through the supabase.com steps:
1. Login at https://supabase.com/dashboard
2. Click "New Project," name it `gbrain`, pick a region, and copy the
generated database password — the pooler URL in step 4 must carry it
(replace any `[YOUR-PASSWORD]` placeholder before pasting)
3. Wait ~2 min for the project to initialize
4. Settings → Database → Connection Pooler → Session → copy the URL (port
6543)
Then follow the same secret-read + verify + init flow as Path 1.
### Path 3 (PGLite local)
```bash
# gstack default: voyage-code-3 (1024d) when VOYAGE_API_KEY is set — code
# retrieval beats general-purpose embeddings on real code queries (validated
# A/B). Without the key, gbrain auto-selects (OpenAI 1536d when available).
# Never select gbrain's legacy zeroentropyai recipe for a new brain: its hosted
# API's sunset date (September 4, 2026) has passed; the wireup helper warns existing installs.
set -- # flags ride the positional params — unquoted $VAR breaks under zsh word-splitting (#1798)
if [ -n "${VOYAGE_API_KEY:-}" ]; then
set -- --embedding-model voyage:voyage-code-3 --embedding-dimensions 1024
fi
gbrain init --pglite --json "$@"
```
Done. No network, no secrets (beyond Voyage embedding API calls during sync, if
`VOYAGE_API_KEY` is set — ~$0.18 per 1M tokens, pennies per repo).
### Path 4 (Remote gbrain MCP — HTTP transport with bearer token)
For users whose brain runs on another machine (Tailscale, ngrok, internal
LAN, or a teammate's server). No local gbrain CLI install, no local DB.
This skill registers the remote MCP and stops; ingestion + indexing happens
on the brain host.
**4a. Collect MCP URL.** Prompt the user:
```
Paste your gbrain MCP URL (e.g. https://wintermute.tail554574.ts.net:3131/mcp):
```
Read with plain `read -r` (no secret hygiene needed — the URL alone isn't
a credential). Validate it starts with `https://` (require TLS for any
non-loopback host); refuse `http://` for non-localhost.
**4b. Collect bearer token via the secret-read helper (never argv).**
```bash
. ~/.claude/skills/gstack/bin/gstack-gbrain-lib.sh
read_secret_to_env GBRAIN_MCP_TOKEN "Paste bearer token: " \
--echo-redacted 's/.\{6\}$/***REDACTED***/'
```
**4c. Verify via gstack-gbrain-mcp-verify.** Run the helper; capture the
classified JSON output:
```bash
verify_json=$(GBRAIN_MCP_TOKEN="$GBRAIN_MCP_TOKEN" \
~/.claude/skills/gstack/bin/gstack-gbrain-mcp-verify "$MCP_URL")
status=$(echo "$verify_json" | jq -r .status)
```
If `status != "success"`, the helper has already classified the failure
into NETWORK / AUTH / MALFORMED and emitted a one-line remediation hint.
Surface the hint above the raw error from `error_text` and **STOP** with
a clear "fix and re-run /setup-gbrain" message. Do NOT continue to Step 5a
on a failed verify — partial registration would leave the user with a
half-broken state.
Capture two values from the verify output for downstream steps:
- `SERVER_VERSION` (e.g., `0.27.1`) — written to the CLAUDE.md block in Step 8.
- `URL_FORM_SUPPORTED` (`true|false`) — passed to `gstack-artifacts-init` in
Step 7 to control which form of the brain-admin hookup command is printed.
**4d. (Path 4) Offer local PGLite for code search.** Ask:
> D# — Want symbol-aware code search on this machine?
> Project/branch/task: <one-sentence grounding using detected slug + branch>
> ELI10: The remote brain at `<MCP_URL>` is great for cross-machine knowledge,
> but symbol queries like `gbrain code-def` / `code-refs` / `code-callers` need
> a local index of THIS machine's code. We can spin up a tiny isolated PGLite
> database (~30 seconds, no accounts, ~120 MB disk) just for code, separate
> from your remote brain. Transcripts and artifacts continue routing through
> the artifacts repo to the remote brain — local PGLite stays code-only.
> Stakes: without it, semantic code search in this repo's worktrees falls
> back to Grep.
> Recommendation: A — 30 seconds, no ongoing cost, unlocks the symbol tools.
> Completeness: A=10/10 (full split-engine), B=7/10 (remote-only).
> A) Yes, set up local PGLite for code (recommended)
> ✅ Unlocks `gbrain code-def`, `code-refs`, `code-callers` per worktree
> ✅ Independent engine — won't disturb remote brain or share transcripts
> B) No, remote MCP only
> ✅ Zero local state — only `~/.claude.json` MCP registration
> ❌ Symbol code queries fall back to Grep in this repo's worktrees
> Net: A = full split-engine; B = remote-only.
**If A (Yes)**: install + init local PGLite with rollback-safe semantics:
```bash
~/.claude/skills/gstack/bin/gstack-gbrain-install || exit $?
# At this point the local gbrain CLI is on PATH. Init PGLite, but back up any
# existing ~/.gbrain/config.json first (rollback if init fails).
if [ -f "$HOME/.gbrain/config.json" ]; then
BACKUP="$HOME/.gbrain/config.json.gstack-bak-$(date +%s)"
mv "$HOME/.gbrain/config.json" "$BACKUP"
fi
# gstack default for local code-search PGLite: voyage-code-3 (1024d) when
# VOYAGE_API_KEY is set. It wins the A/B over voyage-4-large and OpenAI
# text-embedding-3-large on this codebase's symbol queries. Falls back to
# gbrain's auto-selected provider when the key isn't present.
set -- # flags ride the positional params — unquoted $VAR breaks under zsh word-splitting (#1798)
if [ -n "${VOYAGE_API_KEY:-}" ]; then
set -- --embedding-model voyage:voyage-code-3 --embedding-dimensions 1024
fi
if ! gbrain init --pglite --json "$@"; then
if [ -n "${BACKUP:-}" ] && [ -f "$BACKUP" ]; then mv "$BACKUP" "$HOME/.gbrain/config.json"; fi
echo "gbrain init failed. Existing config (if any) was restored. PGLite at ~/.gbrain/pglite/ may be in a partial state — \`rm -rf ~/.gbrain/pglite\` to reset." >&2
echo "Continuing setup without local code search; you can re-run /setup-gbrain to retry." >&2
fi
```
Then continue to Step 5a. The remote-http MCP registration in 5a runs
unchanged; the local PGLite is independent of MCP registration (Claude Code talks
to the remote brain via MCP for queries; `gbrain` CLI talks to local PGLite
for code-def/refs/callers).
**If B (No)**: skip the install + init. The local engine stays absent.
`gbrain_local_status` will be `missing-config` (or `no-cli` if gbrain isn't
installed). `/sync-gbrain` will SKIP the code stage cleanly.
**4e. Skip Steps 3, 4 (other paths) and 5 (local doctor) when B was picked.**
When A was picked, Step 3 already ran (via gstack-gbrain-install) and Step 4
already ran (via `gbrain init --pglite`); jump straight to Step 5a. When B
was picked, Steps 3/4/5 are no-ops; also skip Step 7.5 (transcript ingest)
since memory-stage routes through the artifacts pipeline in remote-http mode.
The bearer token (`GBRAIN_MCP_TOKEN`) stays in process env until Step 5a's
`claude mcp add --header` consumes it; then `unset GBRAIN_MCP_TOKEN`
immediately. Token security trade-off documented in
`setup-gbrain/memory.md`: brief argv exposure during `claude mcp add`,
resting state in `~/.claude.json` mode 0600.
### Switch (from detect's existing-engine state)
```bash
# Going PGLite → Supabase, collect URL first (Path 1 flow), then:
timeout 180s gbrain migrate --to supabase --url "$URL" --json
# Going Supabase → PGLite:
timeout 180s gbrain migrate --to pglite --json
```
If `timeout` returns 124 (exit code for timeout): surface this message
("Migration didn't complete in 3 minutes — another gstack session may be
holding a lock on the source brain. Close other workspaces and re-run
`/setup-gbrain --switch`. Your original brain is untouched."). STOP.