Skip to content

Commit 8241949

Browse files
garrytanclaude
andauthored
v1.57.9.0 feat: source-clean gbrain render (dev-setup --out-dir + machine-wide gbrain-refresh) (garrytan#1951)
* feat(gbrain-detect): add --is-ok live-detection exit-code gate Single source of truth for 'is gbrain usable'. Runs live detection (never reads the possibly-stale gbrain-detection.json) and exits 0 iff status is ok, so setup, bin/dev-setup, and gstack-config can gate brain-aware rendering on one shared check instead of re-grepping the JSON. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(gen-skill-docs): add --out-dir with surgical section-path rewrite --out-dir <abs-dir> mirrors the Claude skill tree (SKILL.md + sections) into a separate directory instead of writing in place, and rewrites the literal section-base path (~/.claude/skills/gstack/<skill>/sections/) in generated content to point at the out-dir. The rewrite is surgical: only /sections/ paths move; bin/, browse/, docs/ references stay pointed at the global install. Global extras (proactive-suggestions.json) are skipped in out-dir mode. Default (no flag) behavior is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dev-setup): render gbrain :user variant to an untracked workspace dir Stops the dev/Conductor workspace from dirtying tracked SKILL.md source. setup honors GSTACK_SKIP_GBRAIN_REGEN (passed inline by dev-setup, never exported) and skips the in-place :user regen; detection is still persisted (PID-unique tmp so concurrent workspaces can't clobber it). dev-setup instead renders the :user variant into .claude/gstack-rendered (gitignored, per-workspace) and repoints the workspace SKILL.md symlinks at it, so the workspace gets brain-aware blocks while the worktree stays canonical. dev-teardown removes the render. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dev-skill): refresh the untracked brain-aware render on template change After the default in-place regen (which keeps the worktree canonical and runs validation), also re-render the :user variant into .claude/gstack-rendered when it exists, so live template edits reflect at the workspace's runtime. Never creates the render dir during plain template dev. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(gstack-config): gbrain-refresh renders brain-aware blocks into the install Extends gbrain-refresh to render the :user variant into the global install (~/.claude/skills/gstack) so every project's Claude sessions get brain-aware blocks, not just the gstack dev workspace. Guarded against mutating the wrong directory: the target must exist, not be a symlink (a symlinked install points at a dev worktree), and look like a real gstack clone (VERSION + package.json). Idempotent and self-documenting. CLAUDE.md's deploy section now notes that 'git reset --hard' reverts the blocks and to re-run gbrain-refresh. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test: cover gstack-gbrain-detect --is-ok + dev-skill render refresh Fills the two automated-coverage gaps from the eng review: --is-ok exit-code gate (no-cli -> nonzero, healthy -> 0, plus an agrees-with-JSON no-skew check reusing the deterministic fake-gbrain harness) and a static tripwire that dev-skill re-renders the :user variant into the workspace render dir only when it already exists. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: bump version and changelog (v1.57.9.0) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: document brain-aware dev-setup render for v1.57.9.0 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 421460f commit 8241949

17 files changed

Lines changed: 590 additions & 22 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ make-pdf/dist/
77
bin/gstack-global-discover*
88
.gstack/
99
.claude/skills/
10+
.claude/gstack-rendered/
1011
.claude/scheduled_tasks.lock
1112
.claude/*.lock
1213
.agents/

CHANGELOG.md

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

3+
## [1.57.9.0] - 2026-06-09
4+
5+
## **Your gstack checkout stays clean when gbrain is installed.**
6+
## **Brain-aware skill blocks render to an untracked spot, never into tracked source.**
7+
8+
Before this, finishing a Conductor or dev-workspace setup with gbrain installed
9+
rewrote 16 planning and review SKILL.md files in place, adding 326 lines of
10+
brain-aware blocks straight into tracked source. Your working tree came back dirty,
11+
one stray `git add` away from committing a token regression for everyone who does
12+
not run gbrain. Now `gen-skill-docs --out-dir` renders the brain-aware variant into
13+
an untracked per-workspace directory, and `bin/dev-setup` repoints the workspace's
14+
skill symlinks at it. The dev workspace gets the full gbrain experience (context-load
15+
and save-to-brain blocks live at runtime), while the tracked SKILL.md files stay
16+
byte-for-byte canonical. To turn the blocks on across all your projects' Claude
17+
sessions, `gstack-config gbrain-refresh` now renders them into your global install,
18+
guarded so it never mutates a symlinked or non-gstack directory.
19+
20+
### The numbers that matter
21+
22+
Structural facts of the change, verifiable from the diff plus `bun run gen:skill-docs`
23+
(zero drift) and the new behavioral test (`test/gen-skill-docs-out-dir.test.ts`).
24+
25+
| When gbrain is installed | Before | After |
26+
|---|---|---|
27+
| Tracked SKILL.md files dirtied by dev-setup | 16 (+326 lines) | 0 |
28+
| Where brain-aware blocks render in a dev workspace | in-place, tracked source | `.claude/gstack-rendered/`, untracked |
29+
| Brain-aware blocks across other projects | re-run `./setup` or hand-edit | `gstack-config gbrain-refresh` (idempotent) |
30+
| "Is gbrain usable" check | per-caller JSON grep, can read stale state | `gstack-gbrain-detect --is-ok` (one live gate) |
31+
32+
The section-path rewrite is surgical: only `~/.claude/skills/gstack/<skill>/sections/`
33+
references move to the render dir, so `bin/` and `docs/` references still resolve to
34+
the install.
35+
36+
### What this means for you
37+
38+
If you develop gstack with gbrain on, `git status` is clean again after setup, and
39+
you can stop fishing brain-block drift out of your commits. After a
40+
`git reset --hard` deploy of your install, re-run `gstack-config gbrain-refresh` to
41+
restore the machine-wide blocks (it is idempotent, and the deploy note in CLAUDE.md
42+
spells this out).
43+
44+
### Itemized changes
45+
46+
#### Added
47+
- `gen-skill-docs --out-dir <dir>`: render the Claude SKILL.md + sections into a
48+
separate directory instead of in place, rewriting only the section-base path so
49+
section reads resolve to the render. Default (no flag) output is unchanged.
50+
- `gstack-gbrain-detect --is-ok`: live-detection exit-code gate (0 iff gbrain is
51+
usable), so setup, dev-setup, and gstack-config share one check.
52+
- `gstack-config gbrain-refresh` now renders brain-aware blocks into the global
53+
install (`~/.claude/skills/gstack`), guarded against symlinked or non-gstack
54+
targets and self-documenting about the `reset --hard` re-run cycle.
55+
56+
#### Changed
57+
- `bin/dev-setup` renders the brain-aware variant into `.claude/gstack-rendered`
58+
(gitignored) and repoints workspace skill symlinks at it; the worktree stays
59+
canonical. `GSTACK_SKIP_GBRAIN_REGEN` is passed inline to the nested setup, never
60+
exported.
61+
- `setup` honors `GSTACK_SKIP_GBRAIN_REGEN` (skips the in-place brain regen on dev
62+
trees) and writes detection state to a PID-unique tmp so concurrent workspaces
63+
cannot clobber it.
64+
- `scripts/dev-skill.ts` refreshes the workspace render on template change, only
65+
when the render dir already exists.
66+
- `bin/dev-teardown` removes the untracked render.
67+
68+
#### For contributors
69+
- New tests: `test/gen-skill-docs-out-dir.test.ts` (behavioral: worktree unchanged,
70+
blocks rendered, section paths rewritten), `test/dev-setup-render-isolation.test.ts`
71+
and `test/gbrain-refresh-install-render.test.ts` (static tripwires), plus
72+
`--is-ok` coverage in `test/gbrain-detect-shape.test.ts`.
73+
374
## [1.57.8.0] - 2026-06-09
475

576
## **`browse` is now the one Chromium on the box, for offline rendering too.**

CLAUDE.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,12 @@ The active skill lives at `~/.claude/skills/gstack/`. After making changes:
883883
2. Fetch and reset in the skill directory: `cd ~/.claude/skills/gstack && git fetch origin && git reset --hard origin/main`
884884
3. Rebuild: `cd ~/.claude/skills/gstack && bun run build`
885885

886+
**If you use gbrain:** the `git reset --hard` in step 2 reverts the brain-aware
887+
(`GBRAIN_CONTEXT_LOAD` / `GBRAIN_SAVE_RESULTS`) blocks that `gstack-config
888+
gbrain-refresh` renders into the install (those generated blocks differ from
889+
`main` by design). After deploying, re-run `gstack-config gbrain-refresh` to
890+
restore them across all your projects' Claude sessions. It's idempotent.
891+
886892
Or copy the binaries directly:
887893
- `cp browse/dist/browse ~/.claude/skills/gstack/browse/dist/browse`
888894
- `cp design/dist/design ~/.claude/skills/gstack/design/dist/design`

CONTRIBUTING.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,22 @@ bun run build
106106
bin/dev-teardown
107107
```
108108

109+
### Brain-aware blocks in a dev workspace (gbrain installed)
110+
111+
If gbrain is installed and usable (`bin/gstack-gbrain-detect --is-ok` exits 0),
112+
`bin/dev-setup` keeps your tracked `SKILL.md` files canonical and renders the
113+
brain-aware variant (the `GBRAIN_CONTEXT_LOAD` / `GBRAIN_SAVE_RESULTS` blocks)
114+
into `.claude/gstack-rendered/` (gitignored, per-workspace). It then repoints the
115+
workspace's `SKILL.md` symlinks at that render, so your Claude sessions get the
116+
full gbrain experience while `git status` stays clean. Under the hood, dev-setup
117+
passes `GSTACK_SKIP_GBRAIN_REGEN=1` inline to the nested `./setup` (so it never
118+
dirties tracked source) and runs `gen:skill-docs:user --out-dir .claude/gstack-rendered`,
119+
which rewrites only the section-base paths to point at the render. `bin/dev-teardown`
120+
removes the render. To make the blocks live across your *other* projects' Claude
121+
sessions, run `gstack-config gbrain-refresh`, which renders them into the global
122+
install (`~/.claude/skills/gstack`), guarded so it never touches a symlinked or
123+
non-gstack directory.
124+
109125
## Testing & evals
110126

111127
### Setup
@@ -334,8 +350,8 @@ If you're using [Conductor](https://conductor.build) to run multiple Claude Code
334350

335351
| Hook | Script | What it does |
336352
|------|--------|-------------|
337-
| `setup` | `bin/dev-setup` | Copies `.env` from main worktree, installs deps, symlinks skills, runs `./setup` non-interactively |
338-
| `archive` | `bin/dev-teardown` | Removes skill symlinks, cleans up `.claude/` directory |
353+
| `setup` | `bin/dev-setup` | Copies `.env` from main worktree, installs deps, symlinks skills, runs `./setup` non-interactively, and (if gbrain is installed) renders brain-aware blocks into `.claude/gstack-rendered/` without dirtying tracked source |
354+
| `archive` | `bin/dev-teardown` | Removes skill symlinks, the `.claude/gstack-rendered/` render, and cleans up `.claude/` directory |
339355

340356
When Conductor creates a new workspace, `bin/dev-setup` runs automatically. It detects the main worktree (via `git worktree list`), copies your `.env` so API keys carry over, and sets up dev mode — no manual steps needed.
341357

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.57.8.0
1+
1.57.9.0

bin/dev-setup

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,56 @@ fi
7272
# no-op skip (no install, no decline marker). A dev workspace must never mutate
7373
# global settings.json. To install the hooks, run `./setup --plan-tune-hooks`
7474
# directly (outside dev-setup). Saved prefix/other config preferences still apply.
75-
"$GSTACK_LINK/setup" --plan-tune-hooks=prompt </dev/null
75+
#
76+
# GSTACK_SKIP_GBRAIN_REGEN=1 is passed INLINE (not exported) so it scopes to
77+
# exactly this nested setup call and can't leak into any other setup path. It
78+
# tells setup NOT to regenerate the gbrain :user variant into the tracked
79+
# worktree (that would dirty checked-in source). We render it into an untracked
80+
# per-workspace dir below instead.
81+
GSTACK_SKIP_GBRAIN_REGEN=1 "$GSTACK_LINK/setup" --plan-tune-hooks=prompt </dev/null
82+
83+
# 7. Brain-aware (gbrain) blocks — render into an untracked workspace dir.
84+
#
85+
# The worktree's SKILL.md files stay canonical (the guard above). If gbrain is
86+
# installed, render the :user variant (with GBRAIN_CONTEXT_LOAD +
87+
# GBRAIN_SAVE_RESULTS) into .claude/gstack-rendered (gitignored, per-workspace)
88+
# and repoint the workspace's SKILL.md symlinks at it. gen-skill-docs --out-dir
89+
# also rewrites the section-base path so section reads resolve to the render, not
90+
# the global install. Result: this workspace gets the full gbrain experience
91+
# while git stays clean. Other projects pick up blocks via `gstack-config
92+
# gbrain-refresh` (printed below).
93+
GBRAIN_DETECT="$REPO_ROOT/bin/gstack-gbrain-detect"
94+
RENDER_DIR="$REPO_ROOT/.claude/gstack-rendered"
95+
if [ -x "$GBRAIN_DETECT" ] && "$GBRAIN_DETECT" --is-ok 2>/dev/null; then
96+
echo ""
97+
echo "gbrain detected — rendering brain-aware skills into .claude/gstack-rendered (workspace-only, untracked)..."
98+
rm -rf "$RENDER_DIR"
99+
if ( cd "$REPO_ROOT" && bun run gen:skill-docs:user --host claude --out-dir "$RENDER_DIR" >/dev/null 2>&1 ); then
100+
# Repoint each project-local SKILL.md symlink whose worktree target has a
101+
# rendered counterpart. The skill DIRECTORY name (basename of the symlink
102+
# target's dir) maps to RENDER_DIR/<dir>/SKILL.md, which is robust to
103+
# frontmatter renames and the gstack- prefix on the link name.
104+
repointed=0
105+
for skill_link in "$REPO_ROOT"/.claude/skills/*/SKILL.md; do
106+
[ -L "$skill_link" ] || continue
107+
target="$(readlink "$skill_link")"
108+
skilldir="$(basename "$(dirname "$target")")"
109+
rendered="$RENDER_DIR/$skilldir/SKILL.md"
110+
if [ -f "$rendered" ]; then ln -snf "$rendered" "$skill_link"; repointed=$((repointed + 1)); fi
111+
done
112+
echo " $repointed workspace skills now serve brain-aware blocks (worktree stays canonical)."
113+
else
114+
echo " warning: brain-aware render failed — workspace uses canonical skills."
115+
fi
116+
fi
76117

77118
echo ""
78119
echo "Dev mode active. Skills resolve from this working tree."
79120
echo " .claude/skills/gstack → $REPO_ROOT"
80121
echo " .agents/skills/gstack → $REPO_ROOT"
81122
echo "Edit any SKILL.md and test immediately — no copy/deploy needed."
82123
echo ""
124+
echo "To make brain-aware blocks live across your OTHER projects too, run:"
125+
echo " gstack-config gbrain-refresh"
126+
echo ""
83127
echo "To tear down: bin/dev-teardown"

bin/dev-teardown

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,16 @@ if [ -d "$CLAUDE_SKILLS" ]; then
2424
fi
2525

2626
rmdir "$CLAUDE_SKILLS" 2>/dev/null || true
27-
rmdir "$REPO_ROOT/.claude" 2>/dev/null || true
2827
fi
2928

29+
# ─── Clean up the untracked brain-aware render (bin/dev-setup step 7) ──
30+
RENDER_DIR="$REPO_ROOT/.claude/gstack-rendered"
31+
if [ -d "$RENDER_DIR" ]; then
32+
rm -rf "$RENDER_DIR"
33+
removed+=("claude/gstack-rendered")
34+
fi
35+
rmdir "$REPO_ROOT/.claude" 2>/dev/null || true
36+
3037
# ─── Clean up .agents/skills/ ────────────────────────────────
3138
AGENTS_SKILLS="$REPO_ROOT/.agents/skills"
3239
if [ -d "$AGENTS_SKILLS" ]; then

bin/gstack-config

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,8 +396,29 @@ case "${1:-}" in
396396

397397
case "$STATUS" in
398398
ok)
399-
echo "Detected gbrain v$VERSION → brain-aware blocks will render in planning-skill SKILL.md files."
400-
echo "Run 'bun run gen:skill-docs' in the gstack repo (or re-run ./setup) to regenerate now."
399+
echo "Detected gbrain v$VERSION."
400+
# Render brain-aware blocks INTO the global install so EVERY project's
401+
# Claude sessions get them (other projects read SKILL.md + sections from
402+
# ~/.claude/skills/gstack via absolute paths baked at gen time). Guards
403+
# (never mutate an arbitrary directory): the target must exist, not be a
404+
# symlink (a symlinked install points at a dev worktree — rendering there
405+
# would dirty tracked source), and look like a real gstack clone.
406+
INSTALL_DIR="$HOME/.claude/skills/gstack"
407+
if [ ! -d "$INSTALL_DIR" ]; then
408+
echo "No global install at $INSTALL_DIR — nothing to render. (Dev workspaces get blocks via bin/dev-setup.)"
409+
elif [ -L "$INSTALL_DIR" ]; then
410+
echo "Skip: $INSTALL_DIR is a symlink (likely a dev worktree). Rendering there would dirty tracked source — run bin/dev-setup in that worktree instead."
411+
elif [ ! -f "$INSTALL_DIR/VERSION" ] || [ ! -f "$INSTALL_DIR/package.json" ]; then
412+
echo "Skip: $INSTALL_DIR doesn't look like a gstack clone (missing VERSION/package.json) — refusing to modify it."
413+
elif ! command -v bun >/dev/null 2>&1; then
414+
echo "Skip: bun not on PATH — can't render. Install bun, then re-run 'gstack-config gbrain-refresh'."
415+
elif ( cd "$INSTALL_DIR" && bun run gen:skill-docs:user --host claude >/dev/null 2>&1 ); then
416+
echo "Rendered brain-aware blocks into $INSTALL_DIR — now live across all your projects' Claude sessions."
417+
echo "Note: this dirties the install's git tree (generated blocks differ from main, by design)."
418+
echo " A 'git reset --hard origin/main' there reverts them; re-run 'gstack-config gbrain-refresh' to restore."
419+
else
420+
echo "Warning: render failed. Run 'cd $INSTALL_DIR && bun run gen:skill-docs:user --host claude' manually to see the error."
421+
fi
401422
;;
402423
*)
403424
echo "gbrain not detected (local-status: $STATUS) → brain-aware blocks will be suppressed in planning-skill SKILL.md files."

bin/gstack-gbrain-detect

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,4 +234,14 @@ function main(): void {
234234
process.stdout.write(JSON.stringify(out, null, 2) + "\n");
235235
}
236236

237+
// --is-ok: live engine-status gate. Exits 0 iff gbrain is usable ("ok"), 1
238+
// otherwise. Runs detection live (never reads the possibly-stale
239+
// gbrain-detection.json), so callers — setup, bin/dev-setup, and
240+
// `gstack-config gbrain-refresh` — can decide whether to render the gbrain
241+
// :user variant without duplicating the JSON grep. Prints nothing on stdout.
242+
if (process.argv.includes("--is-ok")) {
243+
const noCache = process.env.GSTACK_DETECT_NO_CACHE === "1";
244+
process.exit(localEngineStatus({ noCache }) === "ok" ? 0 : 1);
245+
}
246+
237247
main();

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "gstack",
3-
"version": "1.57.8.0",
3+
"version": "1.57.9.0",
44
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
55
"license": "MIT",
66
"type": "module",

0 commit comments

Comments
 (0)