diff --git a/CHANGELOG.md b/CHANGELOG.md index 7286f523d..a91c9d0de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ ## **Conductor workspaces wire `GSTACK_*` keys straight into gbrain embeddings and paid evals.** ## **No more sourcing keys from your shell before every paid run.** -Conductor exposes API keys under a `GSTACK_` prefix so it never collides with whatever the host system has set. The trade-off is that gbrain's embedding pipeline and `@anthropic-ai/claude-agent-sdk` read the canonical `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` names. The new `lib/conductor-env-shim.ts` bridges the gap: it promotes the prefixed form to canonical when canonical is empty. Four TS entry points import the shim as a side effect (`gstack-gbrain-sync.ts`, `gstack-model-benchmark`, `preflight-agent-sdk.ts`, `e2e-helpers.ts`). `USING_GBRAIN_WITH_GSTACK.md` and `CONTRIBUTING.md` document the pattern, plus the checklist for adding the import to new entry points. +Conductor explicitly strips `ANTHROPIC_API_KEY` and `OPENAI_API_KEY` from every workspace's process env, so `.env` copies and `~/.zshrc` exports never reach gbrain's embedding pipeline or `@anthropic-ai/claude-agent-sdk`. The fix path is `GSTACK_ANTHROPIC_API_KEY` / `GSTACK_OPENAI_API_KEY` — Conductor passes those through untouched. The new `lib/conductor-env-shim.ts` closes the loop on the gstack side: it promotes the prefixed form to canonical when canonical is empty. Four TS entry points import the shim as a side effect (`gstack-gbrain-sync.ts`, `gstack-model-benchmark`, `preflight-agent-sdk.ts`, `e2e-helpers.ts`). `README.md`, `USING_GBRAIN_WITH_GSTACK.md`, and `CONTRIBUTING.md` document the pattern, plus the checklist for adding the import to new entry points. ### The numbers that matter diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index df635f75a..e6ee90c75 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -333,7 +333,7 @@ When Conductor creates a new workspace, `bin/dev-setup` runs automatically. It d **First-time setup:** Put your `ANTHROPIC_API_KEY` in `.env` in the main repo (see `.env.example`). Every Conductor workspace inherits it automatically. -**`GSTACK_*` env prefix (Conductor-injected keys).** Recent Conductor versions inject `GSTACK_ANTHROPIC_API_KEY` and `GSTACK_OPENAI_API_KEY` into every workspace's process env directly — independent of the `.env` copy path. The prefix prevents collision with any `ANTHROPIC_API_KEY` you set elsewhere on your system. To keep paid evals, `/sync-gbrain` embeddings, and `claude-agent-sdk` calls working in a Conductor workspace, TS entry points import `lib/conductor-env-shim.ts` as a side effect, which promotes `GSTACK_FOO_API_KEY` to `FOO_API_KEY` when the canonical name is empty. If you add a new TS entry point that hits a paid API, add `import "../lib/conductor-env-shim";` to the top of the file. Today the shim is imported from `bin/gstack-gbrain-sync.ts`, `bin/gstack-model-benchmark`, `scripts/preflight-agent-sdk.ts`, and `test/helpers/e2e-helpers.ts`. +**`GSTACK_*` env prefix (Conductor-injected keys).** Conductor explicitly strips `ANTHROPIC_API_KEY` and `OPENAI_API_KEY` from every workspace's process env. The `.env` copy path doesn't restore them either — the strip happens after env inheritance. Users who want paid evals, `/sync-gbrain` embeddings, or `claude-agent-sdk` calls to work in a Conductor workspace must set `GSTACK_ANTHROPIC_API_KEY` and `GSTACK_OPENAI_API_KEY` in Conductor's workspace env config; Conductor passes those through untouched. On the gstack side, TS entry points import `lib/conductor-env-shim.ts` as a side effect, which promotes `GSTACK_FOO_API_KEY` to `FOO_API_KEY` when the canonical name is empty. If you add a new TS entry point that hits a paid API, add `import "../lib/conductor-env-shim";` to the top of the file. Today the shim is imported from `bin/gstack-gbrain-sync.ts`, `bin/gstack-model-benchmark`, `scripts/preflight-agent-sdk.ts`, and `test/helpers/e2e-helpers.ts`. ## Things to know diff --git a/README.md b/README.md index 54e11ca11..d89b8d998 100644 --- a/README.md +++ b/README.md @@ -388,11 +388,12 @@ I open sourced how I build software. You can fork it and make it your own. /setup-gbrain ``` -Three paths, pick one: +Four paths, pick one: - **Supabase, existing URL** — your cloud agent already provisioned a brain; paste the Session Pooler URL, now this laptop uses the same data. - **Supabase, auto-provision** — paste a Supabase Personal Access Token; the skill creates a new project, polls to healthy, fetches the pooler URL, hands it to `gbrain init`. ~90 seconds end-to-end. - **PGLite local** — zero accounts, zero network, ~30 seconds. Isolated brain on this Mac only. Great for try-first; migrate to Supabase later with `/setup-gbrain --switch`. +- **Remote gbrain MCP** — your brain runs on another machine (Tailscale, ngrok, internal LAN) or a teammate's server; paste an MCP URL and bearer token. Optionally pair with a local PGLite for symbol-aware code search in split-engine mode. Best for cross-machine memory without standing up a local DB. After init, the skill offers to register gbrain as an MCP server for Claude Code (`claude mcp add gbrain -- gbrain serve`) so `gbrain search`, `gbrain put_page`, etc. show up as first-class typed tools — not bash shell-outs. @@ -412,6 +413,8 @@ The skill asks once per repo. The decision is sticky across worktrees and branch gstack-brain-init ``` +**Running gstack in Conductor?** Conductor explicitly strips `ANTHROPIC_API_KEY` and `OPENAI_API_KEY` from every workspace's process env, so paid evals and gbrain embeddings won't work out of the box. Set `GSTACK_ANTHROPIC_API_KEY` and `GSTACK_OPENAI_API_KEY` in Conductor's workspace env config instead — gstack's TS entry points promote them to canonical names at runtime. Full details and the contributor checklist for adding the import to new entry points: [Conductor + GSTACK_* env vars](USING_GBRAIN_WITH_GSTACK.md#conductor--gstack_-env-vars). + **Full monty — every scenario, every flag, every bin helper, every troubleshooting step:** [USING_GBRAIN_WITH_GSTACK.md](USING_GBRAIN_WITH_GSTACK.md) Other references: [docs/gbrain-sync.md](docs/gbrain-sync.md) (sync-specific guide) • [docs/gbrain-sync-errors.md](docs/gbrain-sync-errors.md) (error index) diff --git a/USING_GBRAIN_WITH_GSTACK.md b/USING_GBRAIN_WITH_GSTACK.md index ca0f309b6..ef8052c2f 100644 --- a/USING_GBRAIN_WITH_GSTACK.md +++ b/USING_GBRAIN_WITH_GSTACK.md @@ -258,9 +258,9 @@ Gbrain itself ships with these that gstack wraps: ## Conductor + GSTACK_* env vars -If you run gstack inside a [Conductor](https://conductor.build) workspace, the process env doesn't inherit your interactive shell — `ANTHROPIC_API_KEY` and `OPENAI_API_KEY` are typically empty even when they're set in `~/.zshrc`. Recent Conductor versions instead inject `GSTACK_ANTHROPIC_API_KEY` and `GSTACK_OPENAI_API_KEY` directly into the workspace env. +If you run gstack inside a [Conductor](https://conductor.build) workspace, **Conductor explicitly strips `ANTHROPIC_API_KEY` and `OPENAI_API_KEY` from the workspace env.** Setting them in `~/.zshrc` or `.env` won't help — the strip happens after env inheritance. To get a usable API key into a workspace, set `GSTACK_ANTHROPIC_API_KEY` and `GSTACK_OPENAI_API_KEY` in Conductor's workspace env config instead. Conductor passes those through untouched. -`lib/conductor-env-shim.ts` bridges the gap: when imported as a side effect (`import "../lib/conductor-env-shim";`), it promotes `GSTACK_FOO_API_KEY` to `FOO_API_KEY` for any subprocess that doesn't see the canonical name. The shim is already wired into: +`lib/conductor-env-shim.ts` bridges the gap on the gstack side: when imported as a side effect (`import "../lib/conductor-env-shim";`), it promotes `GSTACK_FOO_API_KEY` to `FOO_API_KEY` for any subprocess that doesn't see the canonical name. The shim is already wired into: - `bin/gstack-gbrain-sync.ts` — so `/sync-gbrain` picks up OpenAI for embeddings - `bin/gstack-model-benchmark` — so `--judge` runs work without manual env mapping