From f87e9ca1f82a72d50440746c487afb01f3904060 Mon Sep 17 00:00:00 2001 From: kajetanma Date: Mon, 20 Jul 2026 10:58:59 +0200 Subject: [PATCH] fix(gbrain): honor GBRAIN_HOME as workspace root, not state dir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gstack-gbrain-detect, gbrain-local-status.ts, and gbrain-exec.ts all resolved GBRAIN_HOME/config.json when GBRAIN_HOME was set, but fell back to $HOME/.gbrain/config.json (nested) when unset. The real gbrain CLI always nests state under a .gbrain dir inside GBRAIN_HOME regardless — confirmed empirically, pointing GBRAIN_HOME straight at the .gbrain dir breaks the CLI with "No brain configured". Net effect for any relocated-GBRAIN_HOME setup: gstack-gbrain-detect always reported gbrain_config_exists:false and gbrain_local_status "missing-config" even with a fully working gbrain install, and buildGbrainEnv silently never seeded DATABASE_URL for spawned gbrain calls. Every /sync-gbrain and /setup-gbrain invocation hit this. Fix: always join GBRAIN_HOME (or the userHome fallback) with ".gbrain" before appending "config.json", in all three places. --- bin/gstack-gbrain-detect | 10 +++++++++- lib/gbrain-exec.ts | 7 ++++++- lib/gbrain-local-status.ts | 12 ++++++++++-- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/bin/gstack-gbrain-detect b/bin/gstack-gbrain-detect index 2100f913b..8253fe796 100755 --- a/bin/gstack-gbrain-detect +++ b/bin/gstack-gbrain-detect @@ -51,8 +51,16 @@ const CONFIG_BIN = join(SCRIPT_DIR, "gstack-config"); // Honors GBRAIN_HOME — must stay consistent with lib/gbrain-local-status's // config resolution, or the detect JSON reports gbrain_local_status "ok" // alongside gbrain_config_exists false for relocated-home users. +// The real `gbrain` CLI always nests state under a `.gbrain` dir inside +// GBRAIN_HOME (GBRAIN_HOME is the workspace root, not the state dir itself — +// confirmed empirically: pointing GBRAIN_HOME straight at the `.gbrain` dir +// breaks the CLI with "No brain configured"). This used to join GBRAIN_HOME +// directly with "config.json" when set, only adding the nested ".gbrain" in +// the unset/default-to-userHome fallback — a relocated-GBRAIN_HOME user +// always got a false gbrain_config_exists:false. const GBRAIN_CONFIG = join( - process.env.GBRAIN_HOME || join(userHome(), ".gbrain"), + process.env.GBRAIN_HOME || userHome(), + ".gbrain", "config.json", ); const CLAUDE_JSON = join(userHome(), ".claude.json"); diff --git a/lib/gbrain-exec.ts b/lib/gbrain-exec.ts index 0cb1ddc57..1dc64972a 100644 --- a/lib/gbrain-exec.ts +++ b/lib/gbrain-exec.ts @@ -98,8 +98,13 @@ export function buildGbrainEnv(opts: BuildGbrainEnvOptions = {}): NodeJS.Process const out: NodeJS.ProcessEnv = { ...baseEnv }; if (baseEnv.GSTACK_RESPECT_ENV_DATABASE_URL === "1") return out; + // GBRAIN_HOME is the workspace root; the real `gbrain` CLI always nests + // its state under a `.gbrain` dir inside it (confirmed empirically — + // pointing GBRAIN_HOME straight at `.gbrain` breaks the CLI). This used + // to join GBRAIN_HOME directly with "config.json", silently failing to + // seed DATABASE_URL for any relocated-GBRAIN_HOME user. const homeBase = baseEnv.HOME || homedir(); - const gbrainHome = baseEnv.GBRAIN_HOME || join(homeBase, ".gbrain"); + const gbrainHome = join(baseEnv.GBRAIN_HOME || homeBase, ".gbrain"); const configPath = join(gbrainHome, "config.json"); if (!existsSync(configPath)) return out; diff --git a/lib/gbrain-local-status.ts b/lib/gbrain-local-status.ts index 2b6caa780..7b4683628 100644 --- a/lib/gbrain-local-status.ts +++ b/lib/gbrain-local-status.ts @@ -114,10 +114,18 @@ export function cacheFilePath(): string { ); } -/** Honors GBRAIN_HOME (codex D11) — same resolution as buildGbrainEnv. */ +/** + * Honors GBRAIN_HOME (codex D11) — same resolution as buildGbrainEnv. + * GBRAIN_HOME is the workspace root; the real `gbrain` CLI always nests its + * state under a `.gbrain` dir inside it (confirmed empirically — pointing + * GBRAIN_HOME straight at `.gbrain` breaks the CLI). This used to join + * GBRAIN_HOME directly with "config.json" when set, only nesting under + * ".gbrain" in the unset/default fallback — a relocated-GBRAIN_HOME user + * always got a false gbrain_config_exists:false. + */ function gbrainConfigPath(env?: NodeJS.ProcessEnv): string { const e = env ?? process.env; - const gbrainHome = e.GBRAIN_HOME || join(userHome(e), ".gbrain"); + const gbrainHome = join(e.GBRAIN_HOME || userHome(e), ".gbrain"); return join(gbrainHome, "config.json"); }