gbrain >= 0.50: JSON `pglite_busy` on stdout makes `gbrain-refresh`/`setup` classify a healthy locked PGLite brain as `broken-config`
- Dominant language
- TypeScript
- Stars
- 133k
- Forks
- 19.9k
- Avg merge
- 18h 46m
- Merged PRs (30d)
- 26
Description
## Summary
With gbrain >= 0.50, `gstack-config gbrain-refresh` (and `./setup`) run inside a live Claude Code session classify a perfectly healthy local PGLite brain as `broken-config` and suppress the brain-aware blocks in every planning-skill SKILL.md.
Root cause: the detection probe `gbrain sources list --json` now reports the held-lock case as a **JSON object on stdout with empty stderr**. `lib/gbrain-local-status.ts` only inspects stderr, matches none of its patterns, and falls through to the defensive `broken-config` default. The accurate status is `engine-locked`, which gstack already treats as usable.
## Environment
- gstack v1.87.0.0 (global git install, macOS, Darwin 27.0.0)
- gbrain 0.50.0.0, `engine: pglite`, MCP registered as `gbrain serve` (local-stdio)
- The Claude Code session's `gbrain serve` MCP process holds the PGLite lock, so any CLI probe from inside that session hits the busy path.
## Repro
1. Have a working PGLite gbrain (`gbrain doctor` ok) and a Claude Code session open with the gbrain MCP registered (so `gbrain serve` holds the lock).
2. From that session run `~/.claude/skills/gstack/bin/gstack-config gbrain-refresh`.
Output:
```
gbrain not detected (local-status: broken-config) → brain-aware blocks will be suppressed in planning-skill SKILL.md files.
Install gbrain (see /setup-gbrain) and re-run 'gstack-config gbrain-refresh' once it's configured.
```
`gstack-gbrain-detect` at the same time reports `gbrain_config_exists: true`, `gbrain_doctor_ok: true`, `gbrain_engine: "pglite"`, but `gbrain_local_status: "broken-config"`.
The exact probe the classifier runs:
```
$ gbrain sources list --json; echo "EXIT=$?"
{"error":"pglite_busy","retryable":true,"reason":"live_serve","next_action":"Wait for the current command or server to close, then retry. Do not remove a live lock."}
EXIT=1
```
stderr is empty. Without `--json`, gbrain prints the human message on stderr ("GBrain's local database is already open through `gbrain serve` (MCP, PID N) ..."), which the existing `already open through` branch (#2194 follow-up) handles correctly. The JSON mode bypasses that branch.
## Impact
- Every `./setup` run inside a Claude session (including the auto-upgrade flow) silently disables gbrain integration in the planning skills, with a remediation message that tells the user to reinstall a working brain.
- The 60s detection cache and `~/.gstack/gbrain-detection.json` then persist the wrong status.
## Fix that works locally
Capture stdout from the failed `execFileSync` and treat the `pglite_busy` JSON like the held-lock stderr message:
```ts
const stderr = (e.stderr ? e.stderr.toString() : "") || "";
// gbrain >= 0.50 with --json reports the held PGLite lock as a JSON object on
// STDOUT ({"error":"pglite_busy","reason":"live_serve",...}) with empty stderr.
const stdout = (e.stdout ? e.stdout.toString() : "") || "";
...
if (stderr.includes("already open through")) {
return configuredEngine(env) === "pglite" ? "engine-locked" : "broken-db";
}
if (stdout.includes("\"pglite_busy\"") || stderr.includes("\"pglite_busy\"")) {
return configuredEngine(env) === "pglite" ? "engine-locked" : "broken-db";
}
```
With that patch `gstack-gbrain-detect` reports `engine-locked` and `gbrain-refresh` renders the brain-aware blocks:
```
Detected gbrain vgbrain0.50.0.0 (local-status: engine-locked).
Rendered brain-aware blocks into ~/.gstack/render/claude — now live across all your projects' Claude sessions.
```
A more robust variant would parse stdout as JSON when it starts with `{` and switch on `error`/`reason`, since gbrain's `--json` error envelope seems to be the direction its CLI is heading. Happy to open a PR if that shape is preferred.
Related: #2194 (same held-lock case, pre-JSON stderr message).
Contributor guide
Research direction
Start in lib/gbrain-local-status.ts and trace the gbrain sources list --json detection probe, focusing on stdout captured from the failed execFileSync call. Treat the reported pglite_busy JSON as the existing held-lock case for a configured PGLite engine. Done when gstack-gbrain-detect reports engine-locked and gbrain-refresh preserves the brain-aware planning-skill blocks instead of classifying the brain as broken-config.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli, developer-experience
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100