mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-12 19:44:48 +01:00
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.
268 lines
11 KiB
Cheetah
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.
|