Skip to content

Commit 5c20900

Browse files
author
knoxjones
committed
chore: merge main into skill frontmatter fix
2 parents 0cfba27 + 3bef43b commit 5c20900

28 files changed

Lines changed: 1232 additions & 111 deletions

CHANGELOG.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,55 @@
11
# Changelog
22

3+
## [1.55.0.0] - 2026-05-30
4+
5+
## **`/sync-gbrain` can no longer be the trigger that lets gbrain delete your repo. The headed browser stops crash-looping, and gbrain installs the current release instead of a pin 23 versions stale.**
6+
7+
gbrain can rm-rf a working tree when its autopilot daemon reclones mid-cycle. `/sync-gbrain` used to call gbrain's `sources remove` and `sync --strategy code` as if they were safe, so it could be the thing that set that race off. Now every destructive gbrain call sits behind feature-detected guards: the orchestrator refuses to run while autopilot is active, refuses to remove a user-managed source it can't storage-protect (it fails closed), canonicalizes paths with realpath so a symlink can't smuggle a delete outside gbrain's own clones, and requires an explicit `--allow-reclone` before a URL-managed source's code walk. Shipped in the same wave: the headed browser's self-inflicted crash-loop is gone, big-brain memory ingests stop getting killed at a fixed 30 minutes, and the gbrain installer moves off its frozen v0.18.2 pin onto the latest release behind a version floor and a `doctor` self-test.
8+
9+
### The numbers that matter
10+
11+
From the shipped diff and its regression suites (`bun test test/gbrain-*.test.ts browse/test/restart-env.test.ts test/memory-ingest-timeout.test.ts`):
12+
13+
| Metric | Before | After | Δ |
14+
|--------|--------|-------|---|
15+
| Destructive gbrain ops behind guards | 0 | 4 | +4 |
16+
| gbrain / brain-sync spawns that work on Windows | 0/8 | 8/8 | +8 |
17+
| gbrain version installed | v0.18.2 (pinned, ~23 behind) | latest + min-version floor + doctor gate | — |
18+
| Memory-ingest timeout | hardcoded 30 min | configurable, checkpoint preserved on timeout | — |
19+
| Generated SKILL.md that parse under strict YAML | partial (colons broke Codex) | all (quoted) | — |
20+
21+
The guard that matters most: a `sources remove` on a source whose files live outside `~/.gbrain/clones/` and can't be storage-protected now refuses instead of proceeding. The path that ate a repo no longer runs unattended.
22+
23+
### What this means for you
24+
25+
If you use `/sync-gbrain`, you are protected from the data-loss race even before gbrain ships its own root fix. "Don't run `/sync-gbrain` while `gbrain autopilot` is active" is now enforced, not just advised, and nothing gets deleted that can't be proven safe. Headed-browser QA against beacon-heavy pages (analytics, live extensions) no longer crash-loops, leaks Chromium, or silently drops to an invisible headless window. New gbrain installs track the current release. Codex and OpenAI can load every gstack skill again.
26+
27+
### Itemized changes
28+
29+
#### Added
30+
- `/sync-gbrain` destructive-op guards (`lib/gbrain-guards.ts`): multi-signal autopilot detection, fail-closed `sources remove`, realpath `remote_url` pre-flight audit, and a `--allow-reclone` gate before URL-managed code walks.
31+
- Install-time gbrain gate (`bin/gstack-gbrain-install`): a minimum-version floor and a `gbrain doctor --fast` self-test, both hard-fail with remediation.
32+
- `GSTACK_INGEST_TIMEOUT_MS` to configure the memory-ingest timeout; on timeout the gbrain checkpoint is preserved so the next run resumes.
33+
34+
#### Changed
35+
- gbrain installs at the latest default-branch HEAD by default; pin a commit with `gstack-gbrain-install --pinned-commit <sha>` for reproducibility.
36+
- Generated SKILL.md descriptions with interior colons are now quoted, so strict YAML loaders (Codex/OpenAI) parse them.
37+
- `/sync-gbrain` guidance: do not run during autopilot; prefer `gbrain sources add --path` over URL-managed sources.
38+
39+
#### Fixed
40+
- `/sync-gbrain` no longer races gbrain's autopilot into a destructive reclone or remove (#1734). Report by @mvanhorn.
41+
- `gstack-jsonl-merge` resolves equal-timestamp entries deterministically across machines, so append-only logs converge instead of re-conflicting forever (#1769). Contributed by @jbetala7.
42+
- Generated SKILL.md frontmatter parses under strict YAML loaders (#1778). Reported by @GilbertzzzZZ, @genisis0x, @cathrynlavery, and @sator-imaging.
43+
- The headed browser daemon no longer crash-loops under load, leaks Chromium processes, or silently downgrades a headed session to headless (#1781).
44+
- `/sync-gbrain --full` memory ingests on large brains are no longer killed at a fixed 30-minute timeout (#1611).
45+
- The gbrain CLI and `gstack-brain-sync` spawn correctly on Windows (#1731).
46+
47+
#### For contributors
48+
- `lib/gbrain-guards.ts` with hermetic tests for every guard branch (autopilot signals, fail-closed remove, reclone gate, realpath containment).
49+
- `parseSourcesList` centralizes `gbrain sources list --json` shape handling across all readers (#1576, whose crash was already fixed in v1.42.0.0 — this removes the last divergent reader).
50+
- Static-grep tripwire (`test/gbrain-spawn-windows-shell.test.ts`) fails CI if a gbrain spawn drops the Windows shell flag.
51+
- gbrain-side requirements for the root fixes (ungated reclone, `--keep-storage`, a cooperative remove-lease, a capability command, true ingest-resume, integration CI) are tracked for the gbrain repo.
52+
353
## [1.54.0.0] - 2026-05-30
454

555
## **The heaviest skill stopped taxing every session. /ship's always-loaded cost dropped 59%, and its prose now loads only when a step needs it.**

CLAUDE.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,4 +938,10 @@ file globs. Run `/sync-gbrain` after meaningful code changes; for ongoing
938938
auto-sync across all worktrees, run `gbrain autopilot --install` once per
939939
machine — gbrain's daemon handles incremental refresh on a schedule.
940940

941+
Safety: don't run `/sync-gbrain` while `gbrain autopilot` is active — the
942+
orchestrator refuses destructive source ops when it detects a running autopilot
943+
to avoid racing it (#1734). Prefer registering user repos with `gbrain sources
944+
add --path <dir>` (no `--url`): URL-managed sources can auto-reclone, and the
945+
sync code walk for them requires an explicit `--allow-reclone` opt-in.
946+
941947
<!-- gstack-gbrain-search-guidance:end -->

USING_GBRAIN_WITH_GSTACK.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ The skill runs three stages — code, memory, brain-sync — independently. A fa
136136

137137
1. **Pre-flight.** Checks `gbrain_local_status` (the local engine's health). If the engine is `broken-db` or `broken-config`, the skill STOPs with a remediation menu — it refuses to silently degrade. If the local engine is missing and you're in remote-MCP mode (Path 4), the code stage SKIPs cleanly and only brain-sync runs.
138138
2. **Code stage.** Registers the cwd as a federated source via `gbrain sources add`, writes a `.gbrain-source` pin file in the repo root (kubectl-style context — every worktree gets its own pin, so Conductor sibling worktrees don't collide), runs `gbrain sync --strategy code`.
139-
3. **Memory stage.** Stages your `~/.gstack/` transcripts + curated memory. In local-stdio MCP mode, ingests into the local engine. In remote-http MCP mode, persists staged markdown to `~/.gstack/transcripts/run-<pid>-<ts>/` for the remote brain admin's pull pipeline.
139+
3. **Memory stage.** Stages your `~/.gstack/` transcripts + curated memory. In local-stdio MCP mode, ingests into the local engine. In remote-http MCP mode, persists staged markdown to `~/.gstack/transcripts/run-<pid>-<ts>/` for the remote brain admin's pull pipeline. The ingest timeout is 30 minutes by default; raise it for a big brain with `GSTACK_INGEST_TIMEOUT_MS` (accepts 1 min–24h). On timeout the gbrain import checkpoint is preserved, so the next `/sync-gbrain` resumes instead of starting over.
140140
4. **Brain-sync stage.** Pushes curated artifacts (plans, designs, retros) to your private artifacts repo if you have one configured.
141141
5. **CLAUDE.md guidance.** Capability-checks the round-trip (write a page → search → find it). If green, writes the `## GBrain Search Guidance` block to your project's CLAUDE.md. If red, REMOVES the block — the agent should never be told to use a tool that isn't installed.
142142

@@ -379,7 +379,7 @@ Another gstack session in a sibling Conductor workspace may be holding a lock on
379379
## Related skills + next steps
380380

381381
- `/health` — includes a GBrain dimension (doctor status, sync queue depth, last-push age) in its 0-10 composite score. The dimension is omitted when gbrain isn't installed; running `/health` on a non-gbrain machine doesn't penalize that choice.
382-
- `/gstack-upgrade` — keeps gstack itself up to date. Does NOT upgrade gbrain independently. To bump gbrain, update `PINNED_COMMIT` in `bin/gstack-gbrain-install` and re-run `/setup-gbrain`.
382+
- `/gstack-upgrade` — keeps gstack itself up to date. Does NOT upgrade gbrain independently. gbrain installs at the latest HEAD by default; to refresh it, `git pull` in your gbrain clone (default `~/gbrain`) and re-run `/setup-gbrain`. Pin a specific commit with `gstack-gbrain-install --pinned-commit <sha>` if you need reproducibility. Installs below the minimum tested version are refused.
383383
- `/retro` — weekly retrospective pulls learnings and plans from your gbrain when memory sync is on, letting the retro reference cross-machine history.
384384

385385
Run `/setup-gbrain` and see what sticks.

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.54.1.0
1+
1.55.0.0

bin/gstack-gbrain-install

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,14 @@
1919
# - git
2020
# - network reachability to https://github.com
2121
#
22-
# The pinned commit is declared here rather than resolved dynamically so
23-
# upgrades are explicit and reviewable. Update PINNED_COMMIT when gstack
24-
# verifies compatibility with a new gbrain release.
22+
# gbrain installs at the latest default-branch HEAD by default — the hard pin
23+
# was removed in #1744 (it had drifted ~23 versions behind). Pass
24+
# --pinned-commit <sha> to install a specific commit for reproducibility. A
25+
# minimum-version floor (MIN_GBRAIN_VERSION) hard-fails the install when the
26+
# resulting gbrain is too old for gstack's sync integration, and a fast
27+
# `gbrain doctor` self-test hard-fails a broken install when gbrain is already
28+
# configured. This keeps the version gate that the pin used to provide without
29+
# freezing users 23 releases behind.
2530
#
2631
# Env:
2732
# GBRAIN_INSTALL_DIR — override default install path (~/gbrain)
@@ -33,8 +38,14 @@
3338
set -euo pipefail
3439

3540
# --- defaults ---
36-
PINNED_COMMIT="08b3698e90532b7b66c445e6b1d8cdfe71822802" # gbrain v0.18.2
37-
PINNED_TAG="v0.18.2"
41+
# No version pin by default — install the latest default-branch HEAD (#1744).
42+
# --pinned-commit <sha> overrides for reproducibility.
43+
PINNED_COMMIT=""
44+
PINNED_TAG=""
45+
# Minimum gbrain version gstack's integration is known to work with. The
46+
# `sources list --json` wrapped-object shape + federated sources landed by 0.20;
47+
# older predates the surface gstack drives. Hard-fail below this floor (#1744).
48+
MIN_GBRAIN_VERSION="0.20.0"
3849
GBRAIN_REPO_URL="https://github.com/garrytan/gbrain.git"
3950
DEFAULT_INSTALL_DIR="${GBRAIN_INSTALL_DIR:-$HOME/gbrain}"
4051
INSTALL_DIR="$DEFAULT_INSTALL_DIR"
@@ -113,16 +124,20 @@ elif [ -n "$DETECTED_CLONE" ]; then
113124
else
114125
# Fresh clone path.
115126
if $DRY_RUN; then
116-
log "DRY RUN: would clone $GBRAIN_REPO_URL @ $PINNED_COMMIT$INSTALL_DIR"
127+
log "DRY RUN: would clone $GBRAIN_REPO_URL ${PINNED_COMMIT:+@ $PINNED_COMMIT }$INSTALL_DIR (latest HEAD unless --pinned-commit)"
117128
exit 0
118129
fi
119130
if [ -d "$INSTALL_DIR" ]; then
120131
fail "install dir $INSTALL_DIR exists but is not a valid gbrain clone. Remove it or pass --install-dir <other>."
121132
fi
122133
log "cloning $GBRAIN_REPO_URL$INSTALL_DIR"
123134
git clone --quiet "$GBRAIN_REPO_URL" "$INSTALL_DIR"
124-
( cd "$INSTALL_DIR" && git checkout --quiet "$PINNED_COMMIT" )
125-
log "pinned to $PINNED_COMMIT${PINNED_TAG:+ ($PINNED_TAG)}"
135+
if [ -n "$PINNED_COMMIT" ]; then
136+
( cd "$INSTALL_DIR" && git checkout --quiet "$PINNED_COMMIT" )
137+
log "checked out pinned commit $PINNED_COMMIT${PINNED_TAG:+ ($PINNED_TAG)}"
138+
else
139+
log "installed latest gbrain (default-branch HEAD)"
140+
fi
126141
fi
127142

128143
if $DRY_RUN; then
@@ -195,6 +210,44 @@ fi
195210

196211
log "installed gbrain $actual_version from $INSTALL_DIR"
197212

213+
# --- minimum-version floor (#1744) ---
214+
# Unpinning means new installs track gbrain HEAD. Hard-fail if the resulting
215+
# version is below the floor gstack's sync integration needs — same exit-3 posture
216+
# as the PATH-shadow / version-mismatch failures above. A warning here is exactly
217+
# how the data-loss class slipped through, so this gate fails closed.
218+
version_lt() {
219+
# 0 (true) when $1 < $2 by version sort; equal versions are NOT less-than.
220+
[ "$1" = "$2" ] && return 1
221+
[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -1)" = "$1" ]
222+
}
223+
if version_lt "$actual_norm" "$MIN_GBRAIN_VERSION"; then
224+
echo "" >&2
225+
echo "gstack-gbrain-install: gbrain $actual_version is below the minimum gstack-tested version ($MIN_GBRAIN_VERSION)." >&2
226+
echo " gstack's sync integration needs the v0.20+ source/list surface." >&2
227+
echo " Fix: update the gbrain clone at $INSTALL_DIR to a newer release (git pull), then" >&2
228+
echo " re-run /setup-gbrain. Or pass --pinned-commit <sha> to install a specific newer commit." >&2
229+
echo "" >&2
230+
exit 3
231+
fi
232+
233+
# --- functional self-test when gbrain is already configured (#1744) ---
234+
# When a brain config exists (re-install / detected clone), run a fast doctor as
235+
# a hard gate so a broken gbrain is caught at setup, not at data-loss time.
236+
# Pre-init installs skip this (config not written yet); the full
237+
# `/sync-gbrain --dry-run` self-test runs from /setup-gbrain after `gbrain init`.
238+
_GBRAIN_HOME_CHECK="${GBRAIN_HOME:-$HOME/.gbrain}"
239+
if [ -f "$_GBRAIN_HOME_CHECK/config.json" ]; then
240+
if ! gbrain doctor --fast >/dev/null 2>&1; then
241+
echo "" >&2
242+
echo "gstack-gbrain-install: gbrain $actual_version installed but 'gbrain doctor --fast' failed." >&2
243+
echo " Refusing to leave a broken gbrain in place. Run 'gbrain doctor' to see what's wrong," >&2
244+
echo " fix it, then re-run /setup-gbrain." >&2
245+
echo "" >&2
246+
exit 3
247+
fi
248+
log "gbrain doctor --fast passed"
249+
fi
250+
198251
# v1.40.0.0 post-install validation (T6 / codex review #19): --ignore-scripts
199252
# may skip artifacts gbrain needs at runtime, especially on Windows
200253
# MSYS/MINGW where we DID pass --ignore-scripts. `gbrain --version` above

0 commit comments

Comments
 (0)