From 569cdae04f18db79763cd3c1fc9fe8f6a9b7554c Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 3 Oct 2026 02:14:37 +0000 Subject: [PATCH 01/10] fix(state-root): design-doc discovery reads $GSTACK_STATE_ROOT/projects DESIGN_DOC_DISCOVERY and autoplan's Step 2 design-doc lookup read the literal ~/.gstack/projects path, so under a non-default state root they missed the docs office-hours writes. The block now globs "$GSTACK_STATE_ROOT"/projects, and each caller's bash block (autoplan, plan-ceo/devex/eng-review, the spec-review prerequisite recheck) resolves the root with the guarded gstack-paths eval first. Allowlist: drops the autoplan ls row, both _LOCALDOC rows and the resolver source-comment row from STATE_ROOT_ALLOWLIST. Tests: the eng Design Doc Check fixture installs gstack-paths and seeds docs under a non-default root; the CEO discovery fixture passes an explicit GSTACK_STATE_ROOT. --- autoplan/SKILL.md.tmpl | 3 ++- plan-ceo-review/SKILL.md.tmpl | 1 + plan-devex-review/SKILL.md.tmpl | 1 + plan-eng-review/SKILL.md.tmpl | 1 + scripts/resolvers/design-doc-discovery.ts | 13 +++++++------ scripts/resolvers/spec-review.ts | 1 + test/ceo-finding-fixture.test.ts | 2 +- test/gen-skill-docs.test.ts | 8 +++++--- test/instruction-facts.test.ts | 4 ---- 9 files changed, 19 insertions(+), 15 deletions(-) diff --git a/autoplan/SKILL.md.tmpl b/autoplan/SKILL.md.tmpl index 0cd4b4406..581136c17 100644 --- a/autoplan/SKILL.md.tmpl +++ b/autoplan/SKILL.md.tmpl @@ -39,6 +39,7 @@ allowed-tools: ```bash setopt +o nomatch 2>/dev/null || true # zsh compat +eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}" SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch') {{DESIGN_DOC_DISCOVERY}} @@ -224,7 +225,7 @@ Re-run: copy RESTORE_PATH's bytes to SOURCE_PLAN, then /autoplan. ### Step 2: Read context - Read CLAUDE.md, TODOS.md, git log -30, git diff against the base branch --stat -- Discover design docs: `ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1` +- Discover design docs: `ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-design-*.md 2>/dev/null | head -1`, resolving the state root and slug as the Design Doc Check block does - Detect UI scope: grep the plan for view/rendering terms (component, screen, form, button, modal, layout, dashboard, sidebar, nav, dialog). Require 2+ matches. Exclude false positives ("page" alone, "UI" in acronyms). diff --git a/plan-ceo-review/SKILL.md.tmpl b/plan-ceo-review/SKILL.md.tmpl index 6eaf3530f..878bb35eb 100644 --- a/plan-ceo-review/SKILL.md.tmpl +++ b/plan-ceo-review/SKILL.md.tmpl @@ -112,6 +112,7 @@ Then read CLAUDE.md, TODOS.md, and any existing architecture docs. **Design doc check:** ```bash setopt +o nomatch 2>/dev/null || true # zsh compat +eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}" SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch') {{DESIGN_DOC_DISCOVERY}} diff --git a/plan-devex-review/SKILL.md.tmpl b/plan-devex-review/SKILL.md.tmpl index cfd6ee8f9..4cfa16642 100644 --- a/plan-devex-review/SKILL.md.tmpl +++ b/plan-devex-review/SKILL.md.tmpl @@ -106,6 +106,7 @@ No background exploration before those questions; record unknowns for later. **Design doc check:** ```bash setopt +o nomatch 2>/dev/null || true +eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}" SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch') {{DESIGN_DOC_DISCOVERY}} diff --git a/plan-eng-review/SKILL.md.tmpl b/plan-eng-review/SKILL.md.tmpl index b9f406b6b..45e2b6b9b 100644 --- a/plan-eng-review/SKILL.md.tmpl +++ b/plan-eng-review/SKILL.md.tmpl @@ -126,6 +126,7 @@ Apply throughout, not as extra checks: ### Design Doc Check ```bash setopt +o nomatch 2>/dev/null || true # zsh compat +eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}" if _REVIEW_SLUG=$(~/.claude/skills/gstack/bin/gstack-slug); then eval "$_REVIEW_SLUG" {{DESIGN_DOC_DISCOVERY}} diff --git a/scripts/resolvers/design-doc-discovery.ts b/scripts/resolvers/design-doc-discovery.ts index 757d85efe..4394d10ee 100644 --- a/scripts/resolvers/design-doc-discovery.ts +++ b/scripts/resolvers/design-doc-discovery.ts @@ -2,10 +2,10 @@ * {{DESIGN_DOC_DISCOVERY}} — the canonical design-doc discovery block (#703). * * Finds the design doc a plan review should read: newest branch-scoped doc - * under ~/.gstack/projects//, falling back to newest project-scoped + * under $GSTACK_STATE_ROOT/projects//, falling back to newest project-scoped * doc, then lets a repo-local doc (DESIGN.md or docs/designs/*.md) win when * it is at least as fresh. office-hours dual-writes docs/designs/ alongside - * ~/.gstack, and the committed copy is what teammates see — but a stale old + * the state root, and the committed copy is what teammates see — but a stale old * repo doc must never shadow a newer private session. * * Single source of truth for the freshness-preference logic that previously @@ -16,7 +16,8 @@ * * The fragment carries no code fences — the {{DESIGN_DOC_DISCOVERY}} token * sits inside each caller's ```bash block. Callers must set $SLUG and - * $BRANCH first (and `setopt +o nomatch` for zsh); the block sets $DESIGN + * $BRANCH and resolve $GSTACK_STATE_ROOT through the guarded gstack-paths + * eval first (and `setopt +o nomatch` for zsh); the block sets $DESIGN * and prints "Design doc found: ..." or "No design doc found". */ @@ -27,10 +28,10 @@ import type { TemplateContext } from './types'; * re-check) can interpolate it into their own template strings instead of * embedding a drifting copy. */ -export const DESIGN_DOC_DISCOVERY_BLOCK = `_LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) -[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) +export const DESIGN_DOC_DISCOVERY_BLOCK = `_LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) +[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) # Repo-local docs win when at least as fresh (#703): office-hours dual-writes -# docs/designs/ alongside ~/.gstack, and the committed copy is what teammates +# docs/designs/ alongside the state root, and the committed copy is what teammates # see. A stale old repo doc never shadows a newer private session. _REPOTOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "") _REPODOC="" diff --git a/scripts/resolvers/spec-review.ts b/scripts/resolvers/spec-review.ts index d4fb16a7d..52a734353 100644 --- a/scripts/resolvers/spec-review.ts +++ b/scripts/resolvers/spec-review.ts @@ -258,6 +258,7 @@ Read the resulting doc if found; otherwise continue the standard review. Do not rerun the preamble or re-offer the prerequisite.` : `After /${first} completes, re-run the design doc check: \`\`\`bash setopt +o nomatch 2>/dev/null || true # zsh compat +eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "\${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}" SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch') ${DESIGN_DOC_DISCOVERY_BLOCK} diff --git a/test/ceo-finding-fixture.test.ts b/test/ceo-finding-fixture.test.ts index cc6fc8832..21da98657 100644 --- a/test/ceo-finding-fixture.test.ts +++ b/test/ceo-finding-fixture.test.ts @@ -302,7 +302,7 @@ describe('CEO finding fixture establishes scope before launch', () => { const design = '# Settings export design\n\n## Problem\nOperators need saved settings in a spreadsheet for offline comparison.\n\n## Approach\nReuse the settings API and escape commas, quotes, and newlines in a CSV formatter.\n'; seedCeoFindingProject(cwd, plan, design); const output = execFileSync('bash', ['-c', `SLUG=fixture; BRANCH=main; ${DESIGN_DOC_DISCOVERY_BLOCK}`], { - cwd, env: { PATH: process.env.PATH!, HOME: home }, encoding: 'utf8', timeout: 10_000, + cwd, env: { PATH: process.env.PATH!, HOME: home, GSTACK_STATE_ROOT: path.join(root, 'state') }, encoding: 'utf8', timeout: 10_000, }); expect(output).toBe(`Design doc found: ${path.join(cwd, 'DESIGN.md')}\n`); expect(execFileSync('git', ['show', 'HEAD:DESIGN.md'], { cwd, encoding: 'utf8', timeout: 30_000 })).toBe(design); diff --git a/test/gen-skill-docs.test.ts b/test/gen-skill-docs.test.ts index 7ed82d5b7..990c53a6f 100644 --- a/test/gen-skill-docs.test.ts +++ b/test/gen-skill-docs.test.ts @@ -1905,13 +1905,15 @@ describe('BENEFITS_FROM resolver', () => { fs.chmodSync(helper, 0o755); fs.copyFileSync(path.join(ROOT, 'bin/gstack-state-root.sh'), path.join(path.dirname(helper), 'gstack-state-root.sh')); fs.copyFileSync(path.join(ROOT, 'bin/gstack-remote-identity.sh'), path.join(path.dirname(helper), 'gstack-remote-identity.sh')); - const expected = path.join(home, '.gstack/projects/canonical-override/session-unknown-design-current.md'); - const wrong = path.join(home, '.gstack/projects/project/session-unknown-design-wrong.md'); + fs.copyFileSync(path.join(ROOT, 'bin/gstack-paths'), path.join(path.dirname(helper), 'gstack-paths')); + fs.chmodSync(path.join(path.dirname(helper), 'gstack-paths'), 0o755); + const expected = path.join(dir, 'state/projects/canonical-override/session-unknown-design-current.md'); + const wrong = path.join(dir, 'state/projects/project/session-unknown-design-wrong.md'); for (const file of [expected, wrong]) { fs.mkdirSync(path.dirname(file), {recursive: true}); fs.writeFileSync(file, '# Design fixture\n'); } - const env = {...process.env, HOME: home, GSTACK_HOME: path.join(home, '.gstack'), + const env = {...process.env, HOME: home, GSTACK_HOME: path.join(dir, 'state'), GSTACK_STATE_ROOT: path.join(dir, 'state'), GSTACK_PROJECT_SLUG: 'canonical-override', GIT_CEILING_DIRECTORIES: dir}; for (const command of [initial, recheck]) { expect(command).toContain('if _REVIEW_SLUG=$(~/.claude/skills/gstack/bin/gstack-slug); then'); diff --git a/test/instruction-facts.test.ts b/test/instruction-facts.test.ts index 898b4b790..ac3096595 100644 --- a/test/instruction-facts.test.ts +++ b/test/instruction-facts.test.ts @@ -172,7 +172,6 @@ const PENDING = 'agent reads or writes this literal default-root path; it diverg const SOURCE_COMMENT = 'source comment, not rendered into any skill'; const STATE_ROOT_ALLOWLIST: Array<{ file: string; match: string; reason: string }> = [ - { file: 'autoplan/SKILL.md.tmpl', match: 'ls -t ~/.gstack/projects/$SLUG/*-design-*.md', reason: PENDING }, { file: 'autoplan/SKILL.md.tmpl', match: 'test plan on disk at ~/.gstack/projects/$SLUG/', reason: DESCRIPTION }, { file: 'canary/SKILL.md.tmpl', match: 'Append it to `~/.gstack/projects/$SLUG/canary-history.jsonl`', reason: PENDING }, { file: 'careful/SKILL.md.tmpl', match: '`~/.gstack/projects//careful-patterns.txt` (per-project)', reason: DESCRIPTION }, @@ -201,9 +200,6 @@ const STATE_ROOT_ALLOWLIST: Array<{ file: string; match: string; reason: string { file: 'retro/SKILL.md.tmpl', match: 'Read `~/.gstack/analytics/eureka.jsonl`', reason: PENDING }, { file: 'ship/sections/apple-release.md.tmpl', match: 'to `~/.gstack/projects/$SLUG/apple-effects.log`', reason: PENDING }, { file: 'ship/sections/tests.md.tmpl', match: '`~/.gstack/projects//-evidence.jsonl` — Step 16 cites this', reason: PENDING }, - { file: 'scripts/resolvers/design-doc-discovery.ts', match: '* under ~/.gstack/projects//, falling back', reason: SOURCE_COMMENT }, - { file: 'scripts/resolvers/design-doc-discovery.ts', match: '_LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md', reason: PENDING }, - { file: 'scripts/resolvers/design-doc-discovery.ts', match: '_LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md', reason: PENDING }, { file: 'scripts/resolvers/design.ts', match: 'Glob \\`~/.gstack/projects/$SLUG/designs/**/approved.json\\`', reason: PENDING }, { file: 'scripts/resolvers/learnings.ts', match: '* Learnings are stored per-project at ~/.gstack/projects/{slug}/learnings.jsonl', reason: SOURCE_COMMENT }, { file: 'scripts/resolvers/preamble.ts', match: 'local JSONL append to ~/.gstack/analytics/ (inline, inspectable)', reason: SOURCE_COMMENT }, From 3c3a013a3bbd2115a52e1a8fb3e3831f755cc34b Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 3 Oct 2026 02:14:37 +0000 Subject: [PATCH 02/10] chore: regenerate SKILL.md and context budget after design-doc discovery state-root change --- autoplan/SKILL.md | 16 +++++++++------- plan-ceo-review/SKILL.md | 14 ++++++++------ plan-devex-review/SKILL.md | 14 ++++++++------ plan-eng-review/SKILL.md | 7 ++++--- test/fixtures/context-budget.json | 8 ++++---- 5 files changed, 33 insertions(+), 26 deletions(-) diff --git a/autoplan/SKILL.md b/autoplan/SKILL.md index 39b7eeaf2..f0530ddf7 100644 --- a/autoplan/SKILL.md +++ b/autoplan/SKILL.md @@ -464,12 +464,13 @@ branch name wherever the instructions say "the base branch" or ``. ```bash setopt +o nomatch 2>/dev/null || true # zsh compat +eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}" SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch') -_LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) -[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) +_LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) +[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) # Repo-local docs win when at least as fresh (#703): office-hours dual-writes -# docs/designs/ alongside ~/.gstack, and the committed copy is what teammates +# docs/designs/ alongside the state root, and the committed copy is what teammates # see. A stale old repo doc never shadows a newer private session. _REPOTOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "") _REPODOC="" @@ -533,12 +534,13 @@ Execute every other section at full depth. When the loaded skill's instructions After /office-hours completes, re-run the design doc check: ```bash setopt +o nomatch 2>/dev/null || true # zsh compat +eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}" SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch') -_LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) -[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) +_LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) +[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) # Repo-local docs win when at least as fresh (#703): office-hours dual-writes -# docs/designs/ alongside ~/.gstack, and the committed copy is what teammates +# docs/designs/ alongside the state root, and the committed copy is what teammates # see. A stale old repo doc never shadows a newer private session. _REPOTOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "") _REPODOC="" @@ -747,7 +749,7 @@ Re-run: copy RESTORE_PATH's bytes to SOURCE_PLAN, then /autoplan. ### Step 2: Read context - Read CLAUDE.md, TODOS.md, git log -30, git diff against the base branch --stat -- Discover design docs: `ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1` +- Discover design docs: `ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-design-*.md 2>/dev/null | head -1`, resolving the state root and slug as the Design Doc Check block does - Detect UI scope: grep the plan for view/rendering terms (component, screen, form, button, modal, layout, dashboard, sidebar, nav, dialog). Require 2+ matches. Exclude false positives ("page" alone, "UI" in acronyms). diff --git a/plan-ceo-review/SKILL.md b/plan-ceo-review/SKILL.md index 90fa289eb..b35feffaa 100644 --- a/plan-ceo-review/SKILL.md +++ b/plan-ceo-review/SKILL.md @@ -553,12 +553,13 @@ Then read CLAUDE.md, TODOS.md, and any existing architecture docs. **Design doc check:** ```bash setopt +o nomatch 2>/dev/null || true # zsh compat +eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}" SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch') -_LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) -[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) +_LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) +[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) # Repo-local docs win when at least as fresh (#703): office-hours dual-writes -# docs/designs/ alongside ~/.gstack, and the committed copy is what teammates +# docs/designs/ alongside the state root, and the committed copy is what teammates # see. A stale old repo doc never shadows a newer private session. _REPOTOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "") _REPODOC="" @@ -621,12 +622,13 @@ Execute every other section at full depth. When the loaded skill's instructions After /office-hours completes, re-run the design doc check: ```bash setopt +o nomatch 2>/dev/null || true # zsh compat +eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}" SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch') -_LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) -[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) +_LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) +[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) # Repo-local docs win when at least as fresh (#703): office-hours dual-writes -# docs/designs/ alongside ~/.gstack, and the committed copy is what teammates +# docs/designs/ alongside the state root, and the committed copy is what teammates # see. A stale old repo doc never shadows a newer private session. _REPOTOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "") _REPODOC="" diff --git a/plan-devex-review/SKILL.md b/plan-devex-review/SKILL.md index e17df6166..f885da7ad 100644 --- a/plan-devex-review/SKILL.md +++ b/plan-devex-review/SKILL.md @@ -577,12 +577,13 @@ No background exploration before those questions; record unknowns for later. **Design doc check:** ```bash setopt +o nomatch 2>/dev/null || true +eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}" SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch') -_LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) -[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) +_LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) +[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) # Repo-local docs win when at least as fresh (#703): office-hours dual-writes -# docs/designs/ alongside ~/.gstack, and the committed copy is what teammates +# docs/designs/ alongside the state root, and the committed copy is what teammates # see. A stale old repo doc never shadows a newer private session. _REPOTOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "") _REPODOC="" @@ -820,12 +821,13 @@ Execute every other section at full depth. When the loaded skill's instructions After /office-hours completes, re-run the design doc check: ```bash setopt +o nomatch 2>/dev/null || true # zsh compat +eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}" SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)") BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch') -_LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) -[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) +_LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) +[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) # Repo-local docs win when at least as fresh (#703): office-hours dual-writes -# docs/designs/ alongside ~/.gstack, and the committed copy is what teammates +# docs/designs/ alongside the state root, and the committed copy is what teammates # see. A stale old repo doc never shadows a newer private session. _REPOTOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "") _REPODOC="" diff --git a/plan-eng-review/SKILL.md b/plan-eng-review/SKILL.md index c416b290c..84ea33c82 100644 --- a/plan-eng-review/SKILL.md +++ b/plan-eng-review/SKILL.md @@ -567,12 +567,13 @@ Sanitize every query before it leaves the machine: strip hostnames, IPs, file pa ### Design Doc Check ```bash setopt +o nomatch 2>/dev/null || true # zsh compat +eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}" if _REVIEW_SLUG=$(~/.claude/skills/gstack/bin/gstack-slug); then eval "$_REVIEW_SLUG" - _LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) -[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) + _LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1) +[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t "$GSTACK_STATE_ROOT"/projects/$SLUG/*-design-*.md 2>/dev/null | head -1) # Repo-local docs win when at least as fresh (#703): office-hours dual-writes -# docs/designs/ alongside ~/.gstack, and the committed copy is what teammates +# docs/designs/ alongside the state root, and the committed copy is what teammates # see. A stale old repo doc never shadows a newer private session. _REPOTOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "") _REPODOC="" diff --git a/test/fixtures/context-budget.json b/test/fixtures/context-budget.json index 23f4f73e3..a306af558 100644 --- a/test/fixtures/context-budget.json +++ b/test/fixtures/context-budget.json @@ -2,7 +2,7 @@ "_comment": "Context-budget ratchet ceilings (~tokens). Regenerate: bun test/helpers/capture-context-budget.ts. Headroom: alwaysOnTotal x1.05, eagerPerInvocation x1.1. Graded by test/context-budget-ratchet.test.ts via lib/context-bill.ts checkBudget.", "alwaysOnTotal": 6814, "eagerPerInvocation": { - "autoplan": 17100, + "autoplan": 17209, "benchmark": 7671, "benchmark-models": 3819, "browse": 8137, @@ -44,10 +44,10 @@ "openclaw/skills/gstack-openclaw-office-hours": 4433, "openclaw/skills/gstack-openclaw-retro": 2542, "pair-agent": 11397, - "plan-ceo-review": 20954, + "plan-ceo-review": 21042, "plan-design-review": 20517, - "plan-devex-review": 17816, - "plan-eng-review": 13474, + "plan-devex-review": 17904, + "plan-eng-review": 13518, "plan-tune": 14730, "qa": 13568, "qa-only": 11740, From 1fdda72ab9457c4d51841d14698f6523f6bf8340 Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 3 Oct 2026 02:17:50 +0000 Subject: [PATCH 03/10] fix(state-root): history, report and ledger paths name $GSTACK_STATE_ROOT Agent-facing read/write paths that named the literal ~/.gstack default now name the state root their writers use: - canary-history.jsonl and health-history.jsonl (the blocks above already resolve the root and print PROJECT_DIR) - ios-design-review report: adds {{SLUG_SETUP}} so the report path is the PROJECT_DIR it prints - plan-tune dream-cycle gate's distillation-proposals.json - retro's skill-usage and eureka reads: read the path gstack-retro-metrics prints (it already checks $_gstack_sr_root/analytics) - ship's apple-effects.log durable-effect ledger and the gstack-evidence ledger description (bin/gstack-evidence writes under resolveStateRoot()) Allowlist: drops the nine matching PENDING rows from STATE_ROOT_ALLOWLIST. --- canary/SKILL.md.tmpl | 2 +- health/SKILL.md.tmpl | 4 ++-- ios-design-review/SKILL.md.tmpl | 12 +++++++++--- plan-tune/SKILL.md.tmpl | 2 +- retro/SKILL.md.tmpl | 4 ++-- ship/sections/apple-release.md.tmpl | 2 +- ship/sections/tests.md.tmpl | 2 +- test/instruction-facts.test.ts | 9 --------- 8 files changed, 17 insertions(+), 20 deletions(-) diff --git a/canary/SKILL.md.tmpl b/canary/SKILL.md.tmpl index 05c363051..09beacbd4 100644 --- a/canary/SKILL.md.tmpl +++ b/canary/SKILL.md.tmpl @@ -230,7 +230,7 @@ mkdir -p "$GSTACK_STATE_ROOT"/projects/$SLUG ``` Write a JSONL entry: `{"skill":"canary","timestamp":"","status":"","url":"","duration_min":,"alerts":}` -Append it to `~/.gstack/projects/$SLUG/canary-history.jsonl`; never overwrite history. +Append it to `$GSTACK_STATE_ROOT/projects/$SLUG/canary-history.jsonl` (the directory this block created); never overwrite history. ### Phase 7: Baseline Update diff --git a/health/SKILL.md.tmpl b/health/SKILL.md.tmpl index 92b52df4a..e8b267c5e 100644 --- a/health/SKILL.md.tmpl +++ b/health/SKILL.md.tmpl @@ -290,7 +290,7 @@ DETAILS: Lint (3 warnings) ``` Only when a numeric composite exists, append one JSONL line to -`~/.gstack/projects/$SLUG/health-history.jsonl`. Zero-check and capture-error runs +`$GSTACK_STATE_ROOT/projects/$SLUG/health-history.jsonl` (the `PROJECT_DIR` printed above). Zero-check and capture-error runs must leave any existing history unchanged: ```json @@ -311,7 +311,7 @@ with no `gbrain` field as `null` for that category. ## Step 6: Trend Analysis + Recommendations -Read the last 10 entries from `~/.gstack/projects/$SLUG/health-history.jsonl` (if the +Read the last 10 entries from `$GSTACK_STATE_ROOT/projects/$SLUG/health-history.jsonl` (if the file exists and has prior entries). ```bash diff --git a/ios-design-review/SKILL.md.tmpl b/ios-design-review/SKILL.md.tmpl index f001963dc..e2866da1f 100644 --- a/ios-design-review/SKILL.md.tmpl +++ b/ios-design-review/SKILL.md.tmpl @@ -92,9 +92,15 @@ For each screen in the app, score 0-10 and explain what would push it to 10: ## Output Write a markdown report to -`~/.gstack/projects//ios-design-review-.md`. Include the -screenshots inline. The CEO/eng review skills can reference this report -when planning UI changes. +`$GSTACK_STATE_ROOT/projects//ios-design-review-.md`, using the +`PROJECT_DIR` this block prints: + +```bash +{{SLUG_SETUP}} +``` + +Include the screenshots inline. The CEO/eng review skills can reference this +report when planning UI changes. ## Failure modes diff --git a/plan-tune/SKILL.md.tmpl b/plan-tune/SKILL.md.tmpl index b632a6a69..d89bee65b 100644 --- a/plan-tune/SKILL.md.tmpl +++ b/plan-tune/SKILL.md.tmpl @@ -69,7 +69,7 @@ Each gate is guarded by a marker so the user is prompted at most once per choice `~/.gstack/.declared-setup-prompted` is missing → run `5-Q setup` below. Touch the marker after setup completes OR is declined. 3. **Dream-cycle gate.** If - `~/.gstack/projects//distillation-proposals.json` exists AND has + `$GSTACK_STATE_ROOT/projects//distillation-proposals.json` exists AND has `applied_at` missing on any proposal → run `Dream cycle review` below. Marker: each proposal carries its own `applied_at` so re-firing this gate naturally skips already-handled items. diff --git a/retro/SKILL.md.tmpl b/retro/SKILL.md.tmpl index 4810387ba..fea06db3b 100644 --- a/retro/SKILL.md.tmpl +++ b/retro/SKILL.md.tmpl @@ -158,8 +158,8 @@ Also check `RETRO_REF`: if it is not `origin/` (local-only repo, missin - `RETRO_CONTEXT: present` → Read `~/.gstack/retro-context.md`. It is user-authored and may contain meeting notes, calendar events, decisions, and other context that doesn't appear in git history. Incorporate it into the retro narrative where relevant. - `GREPTILE_HISTORY: present` → Read `~/.gstack/greptile-history.md`. Filter entries to the retro window by date. Count by type: `fix`, `fp`, `already-fixed`. Signal ratio = `(fix + already-fixed) / (fix + already-fixed + fp)`. Skip unparseable lines silently; if no entries fall in the window, skip the Greptile metric row. - `TODOS_FILE: present` → Read `TODOS.md`. Compute: total open TODOs (exclude the `## Completed` section), P0/P1 count, P2 count, items completed this period (Completed entries dated within the window), items added this period (cross-reference `COMMIT:` lines that touched TODOS.md). -- `SKILL_USAGE_LOG: present` → Read `~/.gstack/analytics/skill-usage.jsonl`. Filter to the window by `ts`. Separate skill activations (no `event` field) from hook fires (`event: "hook_fire"`). Aggregate by skill name. -- `EUREKA_LOG: present` → Read `~/.gstack/analytics/eureka.jsonl`. Filter to the window by `ts`. For each eureka moment note the skill that flagged it, the branch, and a one-line summary of the insight. +- `SKILL_USAGE_LOG: present` → Read the path it prints (`$GSTACK_STATE_ROOT/analytics/skill-usage.jsonl`). Filter to the window by `ts`. Separate skill activations (no `event` field) from hook fires (`event: "hook_fire"`). Aggregate by skill name. +- `EUREKA_LOG: present` → Read the path it prints (`$GSTACK_STATE_ROOT/analytics/eureka.jsonl`). Filter to the window by `ts`. For each eureka moment note the skill that flagged it, the branch, and a one-line summary of the insight. ### Step 2: Compute Metrics diff --git a/ship/sections/apple-release.md.tmpl b/ship/sections/apple-release.md.tmpl index 5fc8e3c51..fab789fe6 100644 --- a/ship/sections/apple-release.md.tmpl +++ b/ship/sections/apple-release.md.tmpl @@ -57,7 +57,7 @@ Build this question's options from a LIVE check of installed skills at ask time ## Archive and upload 1. Archive and export the signed Release build with `gym` (it drives xcodebuild and the signing minted in preflight). Projects with custom archive requirements may drop to `xcodebuild archive` directly; the output either way is an App Store-signed `.ipa`. -2. The upload is an external effect: run `pilot` (TestFlight) or `deliver` (App Store) under the durable-effect contract: before executing, append the key `appstore.upload..` to `~/.gstack/projects/$SLUG/apple-effects.log`; if the key is already present from a prior run (crash, retry), treat the upload as possibly-done and do NOT re-run it. Never re-upload on ambiguity; inspect App Store Connect for the build first. +2. The upload is an external effect: run `pilot` (TestFlight) or `deliver` (App Store) under the durable-effect contract: before executing, append the key `appstore.upload..` to `$GSTACK_STATE_ROOT/projects/$SLUG/apple-effects.log` (resolve the state root and slug in the same command that reads or appends it); if the key is already present from a prior run (crash, retry), treat the upload as possibly-done and do NOT re-run it. Never re-upload on ambiguity; inspect App Store Connect for the build first. 3. The cached session, the minted key, and every credential file are env- or file-level secrets: never argv, never echoed, never committed. 4. NEVER demand an app-specific password — the session MINTS the upload key instead. diff --git a/ship/sections/tests.md.tmpl b/ship/sections/tests.md.tmpl index 23dfa90a1..1ae7de964 100644 --- a/ship/sections/tests.md.tmpl +++ b/ship/sections/tests.md.tmpl @@ -24,7 +24,7 @@ Running bare test migrations without INSTANCE hits an orphan DB and corrupts str Run independent test suites in parallel, each wrapped in the evidence ledger. The wrapper is transparent (streams output live, exit code passes through) and records `{command, exit, working-tree fingerprint, log path}` to -`~/.gstack/projects//-evidence.jsonl` — Step 16 cites this +`$GSTACK_STATE_ROOT/projects//-evidence.jsonl` — Step 16 cites this record instead of re-running when the content hasn't changed: ```bash diff --git a/test/instruction-facts.test.ts b/test/instruction-facts.test.ts index ac3096595..2ca9f94de 100644 --- a/test/instruction-facts.test.ts +++ b/test/instruction-facts.test.ts @@ -173,16 +173,12 @@ const SOURCE_COMMENT = 'source comment, not rendered into any skill'; const STATE_ROOT_ALLOWLIST: Array<{ file: string; match: string; reason: string }> = [ { file: 'autoplan/SKILL.md.tmpl', match: 'test plan on disk at ~/.gstack/projects/$SLUG/', reason: DESCRIPTION }, - { file: 'canary/SKILL.md.tmpl', match: 'Append it to `~/.gstack/projects/$SLUG/canary-history.jsonl`', reason: PENDING }, { file: 'careful/SKILL.md.tmpl', match: '`~/.gstack/projects//careful-patterns.txt` (per-project)', reason: DESCRIPTION }, { file: 'design-consultation/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/*-design-*.md"', reason: MANIFEST_GLOB }, { file: 'design-shotgun/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/*-design-*.md"', reason: MANIFEST_GLOB }, { file: 'design-shotgun/SKILL.md.tmpl', match: 'v1 schema at `~/.gstack/projects/$SLUG/taste-profile.json`', reason: DESCRIPTION }, - { file: 'health/SKILL.md.tmpl', match: '`~/.gstack/projects/$SLUG/health-history.jsonl`. Zero-check', reason: PENDING }, - { file: 'health/SKILL.md.tmpl', match: 'Read the last 10 entries from `~/.gstack/projects/$SLUG/health-history.jsonl`', reason: PENDING }, { file: 'investigate/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/learnings.jsonl"', reason: MANIFEST_GLOB }, { file: 'investigate/SKILL.md.tmpl', match: 'glob: "~/.gstack/analytics/eureka.jsonl"', reason: MANIFEST_GLOB }, - { file: 'ios-design-review/SKILL.md.tmpl', match: '`~/.gstack/projects//ios-design-review-.md`', reason: PENDING }, { file: 'land-and-deploy/sections/readiness-gate.md.tmpl', match: 'eval store (`~/.gstack/projects//evals/`', reason: readinessEvalReason }, { file: 'land-and-deploy/sections/readiness-gate.md.tmpl', match: 'EVAL_DIR=~/.gstack/projects/$SLUG/evals', reason: readinessEvalReason }, { file: 'office-hours/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/*-design-*.md"', reason: MANIFEST_GLOB }, @@ -191,15 +187,10 @@ const STATE_ROOT_ALLOWLIST: Array<{ file: string; match: string; reason: string { file: 'office-hours/sections/design-and-handoff.md.tmpl', match: 'The design doc at `~/.gstack/projects/` is automatically discoverable', reason: DESCRIPTION }, { file: 'plan-ceo-review/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/*-design-*.md"', reason: MANIFEST_GLOB }, { file: 'plan-ceo-review/sections/review-sections.md.tmpl', match: 'Keep in `~/.gstack/projects/` only (local, personal reference)', reason: DESCRIPTION }, - { file: 'plan-tune/SKILL.md.tmpl', match: '`~/.gstack/projects//distillation-proposals.json` exists', reason: PENDING }, { file: 'plan-tune/SKILL.md.tmpl', match: 'Logs stay local (`~/.gstack/projects//question-log.jsonl`)', reason: DESCRIPTION }, { file: 'plan-tune/SKILL.md.tmpl', match: '`~/.gstack/projects//question-log.jsonl` — nothing leaves your', reason: DESCRIPTION }, { file: 'retro/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/timeline.jsonl"', reason: MANIFEST_GLOB }, { file: 'retro/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/learnings.jsonl"', reason: MANIFEST_GLOB }, - { file: 'retro/SKILL.md.tmpl', match: 'Read `~/.gstack/analytics/skill-usage.jsonl`', reason: PENDING }, - { file: 'retro/SKILL.md.tmpl', match: 'Read `~/.gstack/analytics/eureka.jsonl`', reason: PENDING }, - { file: 'ship/sections/apple-release.md.tmpl', match: 'to `~/.gstack/projects/$SLUG/apple-effects.log`', reason: PENDING }, - { file: 'ship/sections/tests.md.tmpl', match: '`~/.gstack/projects//-evidence.jsonl` — Step 16 cites this', reason: PENDING }, { file: 'scripts/resolvers/design.ts', match: 'Glob \\`~/.gstack/projects/$SLUG/designs/**/approved.json\\`', reason: PENDING }, { file: 'scripts/resolvers/learnings.ts', match: '* Learnings are stored per-project at ~/.gstack/projects/{slug}/learnings.jsonl', reason: SOURCE_COMMENT }, { file: 'scripts/resolvers/preamble.ts', match: 'local JSONL append to ~/.gstack/analytics/ (inline, inspectable)', reason: SOURCE_COMMENT }, From b7a1d77050ef8b9a3de1d4789f6b7d28e3882c7b Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 3 Oct 2026 02:17:50 +0000 Subject: [PATCH 04/10] chore: regenerate SKILL.md, ship goldens and context budget after history/ledger state-root paths --- canary/SKILL.md | 2 +- health/SKILL.md | 4 ++-- ios-design-review/SKILL.md | 13 ++++++++++--- plan-tune/SKILL.md | 2 +- retro/SKILL.md | 4 ++-- ship/sections/apple-release.md | 2 +- ship/sections/tests.md | 2 +- test/fixtures/context-budget.json | 10 +++++----- test/fixtures/golden/codex-ship-SKILL.md | 2 +- test/fixtures/golden/factory-ship-SKILL.md | 2 +- 10 files changed, 25 insertions(+), 18 deletions(-) diff --git a/canary/SKILL.md b/canary/SKILL.md index ccb6be0d5..62be3abaa 100644 --- a/canary/SKILL.md +++ b/canary/SKILL.md @@ -701,7 +701,7 @@ mkdir -p "$GSTACK_STATE_ROOT"/projects/$SLUG ``` Write a JSONL entry: `{"skill":"canary","timestamp":"","status":"","url":"","duration_min":,"alerts":}` -Append it to `~/.gstack/projects/$SLUG/canary-history.jsonl`; never overwrite history. +Append it to `$GSTACK_STATE_ROOT/projects/$SLUG/canary-history.jsonl` (the directory this block created); never overwrite history. ### Phase 7: Baseline Update diff --git a/health/SKILL.md b/health/SKILL.md index a4201c28d..9caae6350 100644 --- a/health/SKILL.md +++ b/health/SKILL.md @@ -642,7 +642,7 @@ eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p "$GSTA ``` Only when a numeric composite exists, append one JSONL line to -`~/.gstack/projects/$SLUG/health-history.jsonl`. Zero-check and capture-error runs +`$GSTACK_STATE_ROOT/projects/$SLUG/health-history.jsonl` (the `PROJECT_DIR` printed above). Zero-check and capture-error runs must leave any existing history unchanged: ```json @@ -663,7 +663,7 @@ with no `gbrain` field as `null` for that category. ## Step 6: Trend Analysis + Recommendations -Read the last 10 entries from `~/.gstack/projects/$SLUG/health-history.jsonl` (if the +Read the last 10 entries from `$GSTACK_STATE_ROOT/projects/$SLUG/health-history.jsonl` (if the file exists and has prior entries). ```bash diff --git a/ios-design-review/SKILL.md b/ios-design-review/SKILL.md index e74273d17..9a5381626 100644 --- a/ios-design-review/SKILL.md +++ b/ios-design-review/SKILL.md @@ -441,9 +441,16 @@ For each screen in the app, score 0-10 and explain what would push it to 10: ## Output Write a markdown report to -`~/.gstack/projects//ios-design-review-.md`. Include the -screenshots inline. The CEO/eng review skills can reference this report -when planning UI changes. +`$GSTACK_STATE_ROOT/projects//ios-design-review-.md`, using the +`PROJECT_DIR` this block prints: + +```bash +eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}" +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" && mkdir -p "$GSTACK_STATE_ROOT/projects/$SLUG" && echo "PROJECT_DIR: $GSTACK_STATE_ROOT/projects/$SLUG" +``` + +Include the screenshots inline. The CEO/eng review skills can reference this +report when planning UI changes. ## Failure modes diff --git a/plan-tune/SKILL.md b/plan-tune/SKILL.md index f3c01b738..50f5135a3 100644 --- a/plan-tune/SKILL.md +++ b/plan-tune/SKILL.md @@ -419,7 +419,7 @@ Each gate is guarded by a marker so the user is prompted at most once per choice `~/.gstack/.declared-setup-prompted` is missing → run `5-Q setup` below. Touch the marker after setup completes OR is declined. 3. **Dream-cycle gate.** If - `~/.gstack/projects//distillation-proposals.json` exists AND has + `$GSTACK_STATE_ROOT/projects//distillation-proposals.json` exists AND has `applied_at` missing on any proposal → run `Dream cycle review` below. Marker: each proposal carries its own `applied_at` so re-firing this gate naturally skips already-handled items. diff --git a/retro/SKILL.md b/retro/SKILL.md index 797d4b5b6..10a6cf518 100644 --- a/retro/SKILL.md +++ b/retro/SKILL.md @@ -589,8 +589,8 @@ Also check `RETRO_REF`: if it is not `origin/` (local-only repo, missin - `RETRO_CONTEXT: present` → Read `~/.gstack/retro-context.md`. It is user-authored and may contain meeting notes, calendar events, decisions, and other context that doesn't appear in git history. Incorporate it into the retro narrative where relevant. - `GREPTILE_HISTORY: present` → Read `~/.gstack/greptile-history.md`. Filter entries to the retro window by date. Count by type: `fix`, `fp`, `already-fixed`. Signal ratio = `(fix + already-fixed) / (fix + already-fixed + fp)`. Skip unparseable lines silently; if no entries fall in the window, skip the Greptile metric row. - `TODOS_FILE: present` → Read `TODOS.md`. Compute: total open TODOs (exclude the `## Completed` section), P0/P1 count, P2 count, items completed this period (Completed entries dated within the window), items added this period (cross-reference `COMMIT:` lines that touched TODOS.md). -- `SKILL_USAGE_LOG: present` → Read `~/.gstack/analytics/skill-usage.jsonl`. Filter to the window by `ts`. Separate skill activations (no `event` field) from hook fires (`event: "hook_fire"`). Aggregate by skill name. -- `EUREKA_LOG: present` → Read `~/.gstack/analytics/eureka.jsonl`. Filter to the window by `ts`. For each eureka moment note the skill that flagged it, the branch, and a one-line summary of the insight. +- `SKILL_USAGE_LOG: present` → Read the path it prints (`$GSTACK_STATE_ROOT/analytics/skill-usage.jsonl`). Filter to the window by `ts`. Separate skill activations (no `event` field) from hook fires (`event: "hook_fire"`). Aggregate by skill name. +- `EUREKA_LOG: present` → Read the path it prints (`$GSTACK_STATE_ROOT/analytics/eureka.jsonl`). Filter to the window by `ts`. For each eureka moment note the skill that flagged it, the branch, and a one-line summary of the insight. ### Step 2: Compute Metrics diff --git a/ship/sections/apple-release.md b/ship/sections/apple-release.md index 720fe0db2..71767d758 100644 --- a/ship/sections/apple-release.md +++ b/ship/sections/apple-release.md @@ -59,7 +59,7 @@ Build this question's options from a LIVE check of installed skills at ask time ## Archive and upload 1. Archive and export the signed Release build with `gym` (it drives xcodebuild and the signing minted in preflight). Projects with custom archive requirements may drop to `xcodebuild archive` directly; the output either way is an App Store-signed `.ipa`. -2. The upload is an external effect: run `pilot` (TestFlight) or `deliver` (App Store) under the durable-effect contract: before executing, append the key `appstore.upload..` to `~/.gstack/projects/$SLUG/apple-effects.log`; if the key is already present from a prior run (crash, retry), treat the upload as possibly-done and do NOT re-run it. Never re-upload on ambiguity; inspect App Store Connect for the build first. +2. The upload is an external effect: run `pilot` (TestFlight) or `deliver` (App Store) under the durable-effect contract: before executing, append the key `appstore.upload..` to `$GSTACK_STATE_ROOT/projects/$SLUG/apple-effects.log` (resolve the state root and slug in the same command that reads or appends it); if the key is already present from a prior run (crash, retry), treat the upload as possibly-done and do NOT re-run it. Never re-upload on ambiguity; inspect App Store Connect for the build first. 3. The cached session, the minted key, and every credential file are env- or file-level secrets: never argv, never echoed, never committed. 4. NEVER demand an app-specific password — the session MINTS the upload key instead. diff --git a/ship/sections/tests.md b/ship/sections/tests.md index edf969efa..6e18b5a0c 100644 --- a/ship/sections/tests.md +++ b/ship/sections/tests.md @@ -214,7 +214,7 @@ Running bare test migrations without INSTANCE hits an orphan DB and corrupts str Run independent test suites in parallel, each wrapped in the evidence ledger. The wrapper is transparent (streams output live, exit code passes through) and records `{command, exit, working-tree fingerprint, log path}` to -`~/.gstack/projects//-evidence.jsonl` — Step 16 cites this +`$GSTACK_STATE_ROOT/projects//-evidence.jsonl` — Step 16 cites this record instead of re-running when the content hasn't changed: ```bash diff --git a/test/fixtures/context-budget.json b/test/fixtures/context-budget.json index a306af558..8086e6932 100644 --- a/test/fixtures/context-budget.json +++ b/test/fixtures/context-budget.json @@ -7,7 +7,7 @@ "benchmark-models": 3819, "browse": 8137, "browser-skills/hackernews-frontpage": 371, - "canary": 13729, + "canary": 13740, "careful": 962, "codex": 15225, "context-restore": 10489, @@ -26,10 +26,10 @@ "gstack": 4145, "gstack-upgrade": 4711, "guard": 939, - "health": 11782, + "health": 11796, "investigate": 12434, "ios-clean": 8587, - "ios-design-review": 8674, + "ios-design-review": 8772, "ios-fix": 8476, "ios-qa": 11264, "ios-sync": 8602, @@ -48,10 +48,10 @@ "plan-design-review": 20517, "plan-devex-review": 17904, "plan-eng-review": 13518, - "plan-tune": 14730, + "plan-tune": 14732, "qa": 13568, "qa-only": 11740, - "retro": 19015, + "retro": 19031, "review": 19560, "scrape": 6874, "setup-browser-cookies": 3494, diff --git a/test/fixtures/golden/codex-ship-SKILL.md b/test/fixtures/golden/codex-ship-SKILL.md index b4a44cfff..d55d57a7a 100644 --- a/test/fixtures/golden/codex-ship-SKILL.md +++ b/test/fixtures/golden/codex-ship-SKILL.md @@ -939,7 +939,7 @@ Running bare test migrations without INSTANCE hits an orphan DB and corrupts str Run independent test suites in parallel, each wrapped in the evidence ledger. The wrapper is transparent (streams output live, exit code passes through) and records `{command, exit, working-tree fingerprint, log path}` to -`~/.gstack/projects//-evidence.jsonl` — Step 16 cites this +`$GSTACK_STATE_ROOT/projects//-evidence.jsonl` — Step 16 cites this record instead of re-running when the content hasn't changed: ```bash diff --git a/test/fixtures/golden/factory-ship-SKILL.md b/test/fixtures/golden/factory-ship-SKILL.md index 6f29cd2f5..ddde576c4 100644 --- a/test/fixtures/golden/factory-ship-SKILL.md +++ b/test/fixtures/golden/factory-ship-SKILL.md @@ -920,7 +920,7 @@ Running bare test migrations without INSTANCE hits an orphan DB and corrupts str Run independent test suites in parallel, each wrapped in the evidence ledger. The wrapper is transparent (streams output live, exit code passes through) and records `{command, exit, working-tree fingerprint, log path}` to -`~/.gstack/projects//-evidence.jsonl` — Step 16 cites this +`$GSTACK_STATE_ROOT/projects//-evidence.jsonl` — Step 16 cites this record instead of re-running when the content hasn't changed: ```bash From 10d8c1c0277f26ec55c73bba8c4cac74c38aa556 Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 3 Oct 2026 02:18:36 +0000 Subject: [PATCH 05/10] fix(state-root): taste-profile legacy fallback globs $GSTACK_STATE_ROOT designs The legacy approved.json fallback in {{TASTE_PROFILE}} (design-consultation, design-shotgun) named the literal ~/.gstack/projects path while the approval writers use $GSTACK_STATE_ROOT/projects/$SLUG/designs. Allowlist: drops the design.ts PENDING row. Pin (W7a): design-consultation-contract's exact glob string becomes a meaning-level check (legacy fallback names the state-root designs dir and approved.json, and no ~/.gstack literal). --- scripts/resolvers/design.ts | 2 +- test/design-consultation-contract.test.ts | 5 ++++- test/instruction-facts.test.ts | 1 - 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/resolvers/design.ts b/scripts/resolvers/design.ts index 21420784e..8c234a3ea 100644 --- a/scripts/resolvers/design.ts +++ b/scripts/resolvers/design.ts @@ -1410,7 +1410,7 @@ fonts [top-3], colors [top-3], layouts [top-3], aesthetics [top-3]. Bias generation toward these unless the user explicitly requests a different direction. Also avoid their strong rejections: [top-3 rejected per dimension]." -**Legacy fallback:** Glob \`~/.gstack/projects/$SLUG/designs/**/approved.json\`; Read the five newest. Use explicit feedback only, never infer fonts/colors from variant letters. No usable files: continue without a taste profile. +**Legacy fallback:** Glob \`$GSTACK_STATE_ROOT/projects/$SLUG/designs/**/approved.json\` (resolve the root with gstack-paths); Read the five newest. Use explicit feedback only, never infer fonts/colors from variant letters. No usable files: continue without a taste profile. **Conflict handling:** If the current user request contradicts a strong persistent signal (e.g., "make it playful" when taste profile strongly prefers minimal), flag diff --git a/test/design-consultation-contract.test.ts b/test/design-consultation-contract.test.ts index 56fa19f38..fe70b59e0 100644 --- a/test/design-consultation-contract.test.ts +++ b/test/design-consultation-contract.test.ts @@ -193,7 +193,10 @@ test('taste context has defined count and bounded legacy and malformed-profile f expect(text).not.toContain('head -200'); expect(text).toContain('Count retained sessions (at most 50, not lifetime)'); expect(text).toContain('malformed/unreadable uses the legacy fallback'); - expect(text).toContain('Glob `~/.gstack/projects/$SLUG/designs/**/approved.json`'); + const legacy = text.slice(text.indexOf('**Legacy fallback:**'), text.indexOf('**Conflict handling:**')); + expect(legacy).toContain('$GSTACK_STATE_ROOT/projects/$SLUG/designs/'); + expect(legacy).toContain('approved.json'); + expect(legacy).not.toContain('~/.gstack'); expect(text).toContain('Read the five newest'); expect(text).toContain('No usable files: continue without a taste profile'); expect(text).toContain('never infer fonts/colors from variant letters'); diff --git a/test/instruction-facts.test.ts b/test/instruction-facts.test.ts index 2ca9f94de..b468c9e3e 100644 --- a/test/instruction-facts.test.ts +++ b/test/instruction-facts.test.ts @@ -191,7 +191,6 @@ const STATE_ROOT_ALLOWLIST: Array<{ file: string; match: string; reason: string { file: 'plan-tune/SKILL.md.tmpl', match: '`~/.gstack/projects//question-log.jsonl` — nothing leaves your', reason: DESCRIPTION }, { file: 'retro/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/timeline.jsonl"', reason: MANIFEST_GLOB }, { file: 'retro/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/learnings.jsonl"', reason: MANIFEST_GLOB }, - { file: 'scripts/resolvers/design.ts', match: 'Glob \\`~/.gstack/projects/$SLUG/designs/**/approved.json\\`', reason: PENDING }, { file: 'scripts/resolvers/learnings.ts', match: '* Learnings are stored per-project at ~/.gstack/projects/{slug}/learnings.jsonl', reason: SOURCE_COMMENT }, { file: 'scripts/resolvers/preamble.ts', match: 'local JSONL append to ~/.gstack/analytics/ (inline, inspectable)', reason: SOURCE_COMMENT }, { file: 'scripts/resolvers/preamble/generate-completion-status.ts', match: '\\`~/.gstack/analytics/\\`, matching preamble analytics writes', reason: PENDING }, From fc0aacd0809793ca906b4ab6392e51c1934361ae Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 3 Oct 2026 02:18:36 +0000 Subject: [PATCH 06/10] chore: regenerate SKILL.md and context budget after taste-profile state-root glob --- design-consultation/SKILL.md | 2 +- design-shotgun/SKILL.md | 2 +- test/fixtures/context-budget.json | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/design-consultation/SKILL.md b/design-consultation/SKILL.md index a596206d6..2397f1752 100644 --- a/design-consultation/SKILL.md +++ b/design-consultation/SKILL.md @@ -687,7 +687,7 @@ fonts [top-3], colors [top-3], layouts [top-3], aesthetics [top-3]. Bias generation toward these unless the user explicitly requests a different direction. Also avoid their strong rejections: [top-3 rejected per dimension]." -**Legacy fallback:** Glob `~/.gstack/projects/$SLUG/designs/**/approved.json`; Read the five newest. Use explicit feedback only, never infer fonts/colors from variant letters. No usable files: continue without a taste profile. +**Legacy fallback:** Glob `$GSTACK_STATE_ROOT/projects/$SLUG/designs/**/approved.json` (resolve the root with gstack-paths); Read the five newest. Use explicit feedback only, never infer fonts/colors from variant letters. No usable files: continue without a taste profile. **Conflict handling:** If the current user request contradicts a strong persistent signal (e.g., "make it playful" when taste profile strongly prefers minimal), flag diff --git a/design-shotgun/SKILL.md b/design-shotgun/SKILL.md index 99125356d..5a6a35631 100644 --- a/design-shotgun/SKILL.md +++ b/design-shotgun/SKILL.md @@ -578,7 +578,7 @@ fonts [top-3], colors [top-3], layouts [top-3], aesthetics [top-3]. Bias generation toward these unless the user explicitly requests a different direction. Also avoid their strong rejections: [top-3 rejected per dimension]." -**Legacy fallback:** Glob `~/.gstack/projects/$SLUG/designs/**/approved.json`; Read the five newest. Use explicit feedback only, never infer fonts/colors from variant letters. No usable files: continue without a taste profile. +**Legacy fallback:** Glob `$GSTACK_STATE_ROOT/projects/$SLUG/designs/**/approved.json` (resolve the root with gstack-paths); Read the five newest. Use explicit feedback only, never infer fonts/colors from variant letters. No usable files: continue without a taste profile. **Conflict handling:** If the current user request contradicts a strong persistent signal (e.g., "make it playful" when taste profile strongly prefers minimal), flag diff --git a/test/fixtures/context-budget.json b/test/fixtures/context-budget.json index 8086e6932..501f550c2 100644 --- a/test/fixtures/context-budget.json +++ b/test/fixtures/context-budget.json @@ -13,10 +13,10 @@ "context-restore": 10489, "context-save": 10282, "cso": 4700, - "design-consultation": 15614, + "design-consultation": 15627, "design-html": 14322, "design-review": 34519, - "design-shotgun": 13862, + "design-shotgun": 13874, "deslop-shared-libs": 3419, "devex-review": 19735, "diagram": 4264, From d7e9f0b501aa44a6a910d55e3d1eabdb4b629bc2 Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 3 Oct 2026 02:19:26 +0000 Subject: [PATCH 07/10] fix(state-root): completion-status telemetry prose names $GSTACK_STATE_ROOT/analytics gstack-skill-end writes analytics under the resolved state root ($_GH), so the PLAN MODE EXCEPTION note now names $GSTACK_STATE_ROOT/analytics/ instead of the ~/.gstack default. Allowlist: drops the generate-completion-status.ts PENDING row. Pin (W7a): gen-skill-docs 'render documents the analytics sink' now checks that the render names the state-root analytics dir. --- scripts/resolvers/preamble/generate-completion-status.ts | 2 +- test/gen-skill-docs.test.ts | 2 +- test/instruction-facts.test.ts | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/resolvers/preamble/generate-completion-status.ts b/scripts/resolvers/preamble/generate-completion-status.ts index f07009020..eb9f3cf29 100644 --- a/scripts/resolvers/preamble/generate-completion-status.ts +++ b/scripts/resolvers/preamble/generate-completion-status.ts @@ -69,7 +69,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -\`~/.gstack/analytics/\`, matching preamble analytics writes. +\`$GSTACK_STATE_ROOT/analytics/\`, matching preamble analytics writes. \`\`\`bash ${ctx.paths.binDir}/gstack-skill-end --skill "${ctx.skillName}" --outcome OUTCOME \\ diff --git a/test/gen-skill-docs.test.ts b/test/gen-skill-docs.test.ts index 990c53a6f..91939c052 100644 --- a/test/gen-skill-docs.test.ts +++ b/test/gen-skill-docs.test.ts @@ -441,7 +441,7 @@ describe('gen-skill-docs', () => { expect(SKILL_END_SCRIPT).toContain('analytics/skill-usage.jsonl'); // The render still tells the model where telemetry lands. const content = fs.readFileSync(path.join(ROOT, 'SKILL.md'), 'utf-8'); - expect(content).toContain('~/.gstack/analytics'); + expect(content).toContain('$GSTACK_STATE_ROOT/analytics/'); }); test('plan-review generated preambles stay under the Option A budget', () => { diff --git a/test/instruction-facts.test.ts b/test/instruction-facts.test.ts index b468c9e3e..64a74e0cb 100644 --- a/test/instruction-facts.test.ts +++ b/test/instruction-facts.test.ts @@ -193,7 +193,6 @@ const STATE_ROOT_ALLOWLIST: Array<{ file: string; match: string; reason: string { file: 'retro/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/learnings.jsonl"', reason: MANIFEST_GLOB }, { file: 'scripts/resolvers/learnings.ts', match: '* Learnings are stored per-project at ~/.gstack/projects/{slug}/learnings.jsonl', reason: SOURCE_COMMENT }, { file: 'scripts/resolvers/preamble.ts', match: 'local JSONL append to ~/.gstack/analytics/ (inline, inspectable)', reason: SOURCE_COMMENT }, - { file: 'scripts/resolvers/preamble/generate-completion-status.ts', match: '\\`~/.gstack/analytics/\\`, matching preamble analytics writes', reason: PENDING }, ]; describe('templates and resolvers name gstack state only through allowlisted literals', () => { From 3215981a2e9bb1f37701a109e5d3b0abdf820915 Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 3 Oct 2026 02:19:26 +0000 Subject: [PATCH 08/10] chore: regenerate SKILL.md, ship goldens and context budget after telemetry prose state-root change --- SKILL.md | 2 +- autoplan/SKILL.md | 2 +- benchmark-models/SKILL.md | 2 +- benchmark/SKILL.md | 2 +- browse/SKILL.md | 2 +- canary/SKILL.md | 2 +- codex/SKILL.md | 2 +- context-restore/SKILL.md | 2 +- context-save/SKILL.md | 2 +- design-consultation/SKILL.md | 2 +- design-html/SKILL.md | 2 +- design-review/SKILL.md | 2 +- design-shotgun/SKILL.md | 2 +- devex-review/SKILL.md | 2 +- diagram/SKILL.md | 2 +- document-generate/SKILL.md | 2 +- document-release/SKILL.md | 2 +- health/SKILL.md | 2 +- investigate/SKILL.md | 2 +- ios-clean/SKILL.md | 2 +- ios-design-review/SKILL.md | 2 +- ios-fix/SKILL.md | 2 +- ios-qa/SKILL.md | 2 +- ios-sync/SKILL.md | 2 +- land-and-deploy/SKILL.md | 2 +- landing-report/SKILL.md | 2 +- learn/SKILL.md | 2 +- make-pdf/SKILL.md | 2 +- office-hours/SKILL.md | 2 +- open-gstack-browser/SKILL.md | 2 +- pair-agent/SKILL.md | 2 +- plan-ceo-review/SKILL.md | 2 +- plan-design-review/SKILL.md | 2 +- plan-devex-review/SKILL.md | 2 +- plan-eng-review/SKILL.md | 2 +- plan-tune/SKILL.md | 2 +- qa-only/SKILL.md | 2 +- qa/SKILL.md | 2 +- retro/SKILL.md | 2 +- review/SKILL.md | 2 +- scrape/SKILL.md | 2 +- setup-browser-cookies/SKILL.md | 2 +- setup-deploy/SKILL.md | 2 +- setup-gbrain/SKILL.md | 2 +- ship/SKILL.md | 2 +- skillify/SKILL.md | 2 +- spec/SKILL.md | 2 +- sync-gbrain/SKILL.md | 2 +- test-audit/SKILL.md | 2 +- test/fixtures/context-budget.json | 98 +++++++++++----------- test/fixtures/golden/claude-ship-SKILL.md | 2 +- test/fixtures/golden/codex-ship-SKILL.md | 2 +- test/fixtures/golden/factory-ship-SKILL.md | 2 +- 53 files changed, 101 insertions(+), 101 deletions(-) diff --git a/SKILL.md b/SKILL.md index d868e83b5..bf179fc4f 100644 --- a/SKILL.md +++ b/SKILL.md @@ -135,7 +135,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "gstack" --outcome OUTCOME \ diff --git a/autoplan/SKILL.md b/autoplan/SKILL.md index f0530ddf7..2cc659589 100644 --- a/autoplan/SKILL.md +++ b/autoplan/SKILL.md @@ -404,7 +404,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "autoplan" --outcome OUTCOME \ diff --git a/benchmark-models/SKILL.md b/benchmark-models/SKILL.md index 4c6c47dca..d4c4f13ca 100644 --- a/benchmark-models/SKILL.md +++ b/benchmark-models/SKILL.md @@ -139,7 +139,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "benchmark-models" --outcome OUTCOME \ diff --git a/benchmark/SKILL.md b/benchmark/SKILL.md index 9e9b90ad9..874e8ea5d 100644 --- a/benchmark/SKILL.md +++ b/benchmark/SKILL.md @@ -139,7 +139,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "benchmark" --outcome OUTCOME \ diff --git a/browse/SKILL.md b/browse/SKILL.md index 5910fa923..f471c4b71 100644 --- a/browse/SKILL.md +++ b/browse/SKILL.md @@ -135,7 +135,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "browse" --outcome OUTCOME \ diff --git a/canary/SKILL.md b/canary/SKILL.md index 62be3abaa..72deeaa9f 100644 --- a/canary/SKILL.md +++ b/canary/SKILL.md @@ -356,7 +356,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "canary" --outcome OUTCOME \ diff --git a/codex/SKILL.md b/codex/SKILL.md index 8e9c99cc4..69e5f723d 100644 --- a/codex/SKILL.md +++ b/codex/SKILL.md @@ -388,7 +388,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "codex" --outcome OUTCOME \ diff --git a/context-restore/SKILL.md b/context-restore/SKILL.md index 7a6a0a14e..bb75f43c1 100644 --- a/context-restore/SKILL.md +++ b/context-restore/SKILL.md @@ -358,7 +358,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "context-restore" --outcome OUTCOME \ diff --git a/context-save/SKILL.md b/context-save/SKILL.md index 1476c6375..2ab4b73a7 100644 --- a/context-save/SKILL.md +++ b/context-save/SKILL.md @@ -357,7 +357,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "context-save" --outcome OUTCOME \ diff --git a/design-consultation/SKILL.md b/design-consultation/SKILL.md index 2397f1752..3cd1673c8 100644 --- a/design-consultation/SKILL.md +++ b/design-consultation/SKILL.md @@ -411,7 +411,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "design-consultation" --outcome OUTCOME \ diff --git a/design-html/SKILL.md b/design-html/SKILL.md index 6c2532a75..9cec50ffc 100644 --- a/design-html/SKILL.md +++ b/design-html/SKILL.md @@ -363,7 +363,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "design-html" --outcome OUTCOME \ diff --git a/design-review/SKILL.md b/design-review/SKILL.md index 4fc69f108..dfb0c7a90 100644 --- a/design-review/SKILL.md +++ b/design-review/SKILL.md @@ -389,7 +389,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "design-review" --outcome OUTCOME \ diff --git a/design-shotgun/SKILL.md b/design-shotgun/SKILL.md index 5a6a35631..24b3b1dbf 100644 --- a/design-shotgun/SKILL.md +++ b/design-shotgun/SKILL.md @@ -377,7 +377,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "design-shotgun" --outcome OUTCOME \ diff --git a/devex-review/SKILL.md b/devex-review/SKILL.md index 842391b69..e974e649e 100644 --- a/devex-review/SKILL.md +++ b/devex-review/SKILL.md @@ -391,7 +391,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "devex-review" --outcome OUTCOME \ diff --git a/diagram/SKILL.md b/diagram/SKILL.md index bff370829..67b7ac2d4 100644 --- a/diagram/SKILL.md +++ b/diagram/SKILL.md @@ -138,7 +138,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "diagram" --outcome OUTCOME \ diff --git a/document-generate/SKILL.md b/document-generate/SKILL.md index fb4f85c2c..2b318e0a7 100644 --- a/document-generate/SKILL.md +++ b/document-generate/SKILL.md @@ -362,7 +362,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "document-generate" --outcome OUTCOME \ diff --git a/document-release/SKILL.md b/document-release/SKILL.md index bbed8b605..5fcba0f1a 100644 --- a/document-release/SKILL.md +++ b/document-release/SKILL.md @@ -360,7 +360,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "document-release" --outcome OUTCOME \ diff --git a/health/SKILL.md b/health/SKILL.md index 9caae6350..a03661f59 100644 --- a/health/SKILL.md +++ b/health/SKILL.md @@ -358,7 +358,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "health" --outcome OUTCOME \ diff --git a/investigate/SKILL.md b/investigate/SKILL.md index 8678884ae..7a9a05f4f 100644 --- a/investigate/SKILL.md +++ b/investigate/SKILL.md @@ -397,7 +397,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "investigate" --outcome OUTCOME \ diff --git a/ios-clean/SKILL.md b/ios-clean/SKILL.md index 3cf5016b3..834507879 100644 --- a/ios-clean/SKILL.md +++ b/ios-clean/SKILL.md @@ -360,7 +360,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "ios-clean" --outcome OUTCOME \ diff --git a/ios-design-review/SKILL.md b/ios-design-review/SKILL.md index 9a5381626..6bdcd76e5 100644 --- a/ios-design-review/SKILL.md +++ b/ios-design-review/SKILL.md @@ -362,7 +362,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "ios-design-review" --outcome OUTCOME \ diff --git a/ios-fix/SKILL.md b/ios-fix/SKILL.md index e2a59ba05..638a2264d 100644 --- a/ios-fix/SKILL.md +++ b/ios-fix/SKILL.md @@ -363,7 +363,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "ios-fix" --outcome OUTCOME \ diff --git a/ios-qa/SKILL.md b/ios-qa/SKILL.md index e43a89962..23f462a7a 100644 --- a/ios-qa/SKILL.md +++ b/ios-qa/SKILL.md @@ -395,7 +395,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "ios-qa" --outcome OUTCOME \ diff --git a/ios-sync/SKILL.md b/ios-sync/SKILL.md index 66b02d4d2..e0dd137a7 100644 --- a/ios-sync/SKILL.md +++ b/ios-sync/SKILL.md @@ -360,7 +360,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "ios-sync" --outcome OUTCOME \ diff --git a/land-and-deploy/SKILL.md b/land-and-deploy/SKILL.md index 79c3bb124..62d86669b 100644 --- a/land-and-deploy/SKILL.md +++ b/land-and-deploy/SKILL.md @@ -384,7 +384,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "land-and-deploy" --outcome OUTCOME \ diff --git a/landing-report/SKILL.md b/landing-report/SKILL.md index 77795c0d9..99d2170ba 100644 --- a/landing-report/SKILL.md +++ b/landing-report/SKILL.md @@ -357,7 +357,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "landing-report" --outcome OUTCOME \ diff --git a/learn/SKILL.md b/learn/SKILL.md index 4cc270d9a..cf184dd9b 100644 --- a/learn/SKILL.md +++ b/learn/SKILL.md @@ -358,7 +358,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "learn" --outcome OUTCOME \ diff --git a/make-pdf/SKILL.md b/make-pdf/SKILL.md index 2bd3d158b..e61ba1220 100644 --- a/make-pdf/SKILL.md +++ b/make-pdf/SKILL.md @@ -176,7 +176,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "make-pdf" --outcome OUTCOME \ diff --git a/office-hours/SKILL.md b/office-hours/SKILL.md index 80ef8e94e..0de969e06 100644 --- a/office-hours/SKILL.md +++ b/office-hours/SKILL.md @@ -421,7 +421,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "office-hours" --outcome OUTCOME \ diff --git a/open-gstack-browser/SKILL.md b/open-gstack-browser/SKILL.md index 779985f73..7583e9dd3 100644 --- a/open-gstack-browser/SKILL.md +++ b/open-gstack-browser/SKILL.md @@ -137,7 +137,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "open-gstack-browser" --outcome OUTCOME \ diff --git a/pair-agent/SKILL.md b/pair-agent/SKILL.md index 1bde36ff8..7af82fff1 100644 --- a/pair-agent/SKILL.md +++ b/pair-agent/SKILL.md @@ -359,7 +359,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "pair-agent" --outcome OUTCOME \ diff --git a/plan-ceo-review/SKILL.md b/plan-ceo-review/SKILL.md index b35feffaa..61a376067 100644 --- a/plan-ceo-review/SKILL.md +++ b/plan-ceo-review/SKILL.md @@ -407,7 +407,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "plan-ceo-review" --outcome OUTCOME \ diff --git a/plan-design-review/SKILL.md b/plan-design-review/SKILL.md index 6f9922ad1..079b97886 100644 --- a/plan-design-review/SKILL.md +++ b/plan-design-review/SKILL.md @@ -413,7 +413,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "plan-design-review" --outcome OUTCOME \ diff --git a/plan-devex-review/SKILL.md b/plan-devex-review/SKILL.md index f885da7ad..b7a15c449 100644 --- a/plan-devex-review/SKILL.md +++ b/plan-devex-review/SKILL.md @@ -385,7 +385,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "plan-devex-review" --outcome OUTCOME \ diff --git a/plan-eng-review/SKILL.md b/plan-eng-review/SKILL.md index 84ea33c82..00c1cbbe6 100644 --- a/plan-eng-review/SKILL.md +++ b/plan-eng-review/SKILL.md @@ -430,7 +430,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "plan-eng-review" --outcome OUTCOME \ diff --git a/plan-tune/SKILL.md b/plan-tune/SKILL.md index 50f5135a3..1159ef68b 100644 --- a/plan-tune/SKILL.md +++ b/plan-tune/SKILL.md @@ -368,7 +368,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "plan-tune" --outcome OUTCOME \ diff --git a/qa-only/SKILL.md b/qa-only/SKILL.md index 26923f7fb..e939e9d72 100644 --- a/qa-only/SKILL.md +++ b/qa-only/SKILL.md @@ -387,7 +387,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "qa-only" --outcome OUTCOME \ diff --git a/qa/SKILL.md b/qa/SKILL.md index 09327529e..99bcb287a 100644 --- a/qa/SKILL.md +++ b/qa/SKILL.md @@ -391,7 +391,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "qa" --outcome OUTCOME \ diff --git a/retro/SKILL.md b/retro/SKILL.md index 10a6cf518..00d62f6c9 100644 --- a/retro/SKILL.md +++ b/retro/SKILL.md @@ -376,7 +376,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "retro" --outcome OUTCOME \ diff --git a/review/SKILL.md b/review/SKILL.md index 75e1a8ad4..5cbd5d588 100644 --- a/review/SKILL.md +++ b/review/SKILL.md @@ -389,7 +389,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "review" --outcome OUTCOME \ diff --git a/scrape/SKILL.md b/scrape/SKILL.md index ad2701517..91cfed2ee 100644 --- a/scrape/SKILL.md +++ b/scrape/SKILL.md @@ -134,7 +134,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "scrape" --outcome OUTCOME \ diff --git a/setup-browser-cookies/SKILL.md b/setup-browser-cookies/SKILL.md index e2644d8ed..5a1cc7c92 100644 --- a/setup-browser-cookies/SKILL.md +++ b/setup-browser-cookies/SKILL.md @@ -133,7 +133,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "setup-browser-cookies" --outcome OUTCOME \ diff --git a/setup-deploy/SKILL.md b/setup-deploy/SKILL.md index bc9cce297..263161df5 100644 --- a/setup-deploy/SKILL.md +++ b/setup-deploy/SKILL.md @@ -359,7 +359,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "setup-deploy" --outcome OUTCOME \ diff --git a/setup-gbrain/SKILL.md b/setup-gbrain/SKILL.md index 795ba7bc6..938410de2 100644 --- a/setup-gbrain/SKILL.md +++ b/setup-gbrain/SKILL.md @@ -358,7 +358,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "setup-gbrain" --outcome OUTCOME \ diff --git a/ship/SKILL.md b/ship/SKILL.md index 2fc36c6b1..469211a69 100644 --- a/ship/SKILL.md +++ b/ship/SKILL.md @@ -389,7 +389,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "ship" --outcome OUTCOME \ diff --git a/skillify/SKILL.md b/skillify/SKILL.md index cae10b823..335f5c836 100644 --- a/skillify/SKILL.md +++ b/skillify/SKILL.md @@ -357,7 +357,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "skillify" --outcome OUTCOME \ diff --git a/spec/SKILL.md b/spec/SKILL.md index f2d3c2daf..cb5e994cd 100644 --- a/spec/SKILL.md +++ b/spec/SKILL.md @@ -387,7 +387,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "spec" --outcome OUTCOME \ diff --git a/sync-gbrain/SKILL.md b/sync-gbrain/SKILL.md index 6ab27d8cd..3c0a73cff 100644 --- a/sync-gbrain/SKILL.md +++ b/sync-gbrain/SKILL.md @@ -359,7 +359,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "sync-gbrain" --outcome OUTCOME \ diff --git a/test-audit/SKILL.md b/test-audit/SKILL.md index f725326df..2febc8541 100644 --- a/test-audit/SKILL.md +++ b/test-audit/SKILL.md @@ -354,7 +354,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "test-audit" --outcome OUTCOME \ diff --git a/test/fixtures/context-budget.json b/test/fixtures/context-budget.json index 501f550c2..5254cdc48 100644 --- a/test/fixtures/context-budget.json +++ b/test/fixtures/context-budget.json @@ -2,66 +2,66 @@ "_comment": "Context-budget ratchet ceilings (~tokens). Regenerate: bun test/helpers/capture-context-budget.ts. Headroom: alwaysOnTotal x1.05, eagerPerInvocation x1.1. Graded by test/context-budget-ratchet.test.ts via lib/context-bill.ts checkBudget.", "alwaysOnTotal": 6814, "eagerPerInvocation": { - "autoplan": 17209, - "benchmark": 7671, - "benchmark-models": 3819, - "browse": 8137, + "autoplan": 17212, + "benchmark": 7673, + "benchmark-models": 3821, + "browse": 8139, "browser-skills/hackernews-frontpage": 371, - "canary": 13740, + "canary": 13742, "careful": 962, - "codex": 15225, - "context-restore": 10489, - "context-save": 10282, + "codex": 15227, + "context-restore": 10492, + "context-save": 10284, "cso": 4700, - "design-consultation": 15627, - "design-html": 14322, - "design-review": 34519, - "design-shotgun": 13874, + "design-consultation": 15629, + "design-html": 14324, + "design-review": 34521, + "design-shotgun": 13876, "deslop-shared-libs": 3419, - "devex-review": 19735, - "diagram": 4264, - "document-generate": 12115, - "document-release": 10479, + "devex-review": 19738, + "diagram": 4267, + "document-generate": 12118, + "document-release": 10481, "freeze": 1053, - "gstack": 4145, + "gstack": 4147, "gstack-upgrade": 4711, "guard": 939, - "health": 11796, - "investigate": 12434, - "ios-clean": 8587, - "ios-design-review": 8772, - "ios-fix": 8476, - "ios-qa": 11264, - "ios-sync": 8602, - "land-and-deploy": 19111, - "landing-report": 9299, - "learn": 8993, - "make-pdf": 5230, - "office-hours": 22614, - "open-gstack-browser": 4838, + "health": 11798, + "investigate": 12436, + "ios-clean": 8589, + "ios-design-review": 8774, + "ios-fix": 8478, + "ios-qa": 11266, + "ios-sync": 8604, + "land-and-deploy": 19114, + "landing-report": 9301, + "learn": 8996, + "make-pdf": 5233, + "office-hours": 22616, + "open-gstack-browser": 4840, "openclaw/skills/gstack-openclaw-ceo-review": 2764, "openclaw/skills/gstack-openclaw-investigate": 1429, "openclaw/skills/gstack-openclaw-office-hours": 4433, "openclaw/skills/gstack-openclaw-retro": 2542, - "pair-agent": 11397, - "plan-ceo-review": 21042, - "plan-design-review": 20517, - "plan-devex-review": 17904, - "plan-eng-review": 13518, - "plan-tune": 14732, - "qa": 13568, - "qa-only": 11740, - "retro": 19031, - "review": 19560, - "scrape": 6874, - "setup-browser-cookies": 3494, - "setup-deploy": 11369, - "setup-gbrain": 15619, - "ship": 20627, - "skillify": 11957, - "spec": 14807, - "sync-gbrain": 14738, - "test-audit": 10532, + "pair-agent": 11399, + "plan-ceo-review": 21044, + "plan-design-review": 20519, + "plan-devex-review": 17906, + "plan-eng-review": 13521, + "plan-tune": 14734, + "qa": 13570, + "qa-only": 11742, + "retro": 19033, + "review": 19562, + "scrape": 6876, + "setup-browser-cookies": 3497, + "setup-deploy": 11372, + "setup-gbrain": 15621, + "ship": 20629, + "skillify": 11960, + "spec": 14809, + "sync-gbrain": 14740, + "test-audit": 10535, "unfreeze": 448 } } diff --git a/test/fixtures/golden/claude-ship-SKILL.md b/test/fixtures/golden/claude-ship-SKILL.md index 2fc36c6b1..469211a69 100644 --- a/test/fixtures/golden/claude-ship-SKILL.md +++ b/test/fixtures/golden/claude-ship-SKILL.md @@ -389,7 +389,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash ~/.claude/skills/gstack/bin/gstack-skill-end --skill "ship" --outcome OUTCOME \ diff --git a/test/fixtures/golden/codex-ship-SKILL.md b/test/fixtures/golden/codex-ship-SKILL.md index d55d57a7a..8e4096251 100644 --- a/test/fixtures/golden/codex-ship-SKILL.md +++ b/test/fixtures/golden/codex-ship-SKILL.md @@ -396,7 +396,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash $GSTACK_BIN/gstack-skill-end --skill "ship" --outcome OUTCOME \ diff --git a/test/fixtures/golden/factory-ship-SKILL.md b/test/fixtures/golden/factory-ship-SKILL.md index ddde576c4..16d743f0e 100644 --- a/test/fixtures/golden/factory-ship-SKILL.md +++ b/test/fixtures/golden/factory-ship-SKILL.md @@ -377,7 +377,7 @@ preamble's skill-start output echoed. It also drains the artifacts-sync queue (the former skill-end sync step — do not run gstack-brain-sync separately). **PLAN MODE EXCEPTION — ALWAYS RUN:** This writes telemetry to -`~/.gstack/analytics/`, matching preamble analytics writes. +`$GSTACK_STATE_ROOT/analytics/`, matching preamble analytics writes. ```bash $GSTACK_BIN/gstack-skill-end --skill "ship" --outcome OUTCOME \ From 44e9c1ed3ae35d25f28f7c1c4299cd736724b2b4 Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 3 Oct 2026 02:21:06 +0000 Subject: [PATCH 09/10] fix(state-root): gbrain context_queries globs use {gstack_state_root}/ bin/gstack-brain-context-load.ts resolves the {gstack_state_root}/ prefix through gstack-paths (configuredStateGlob); the legacy ~ form only matched the default root. The nine projects/analytics manifest globs in design-consultation, design-shotgun, investigate, office-hours, plan-ceo-review and retro now use the prefix, as does office-hours' builder-profile developer-profile.json glob (plan-tune writes it under $GSTACK_STATE_ROOT). Allowlist: drops the nine MANIFEST_GLOB rows and the now-unused MANIFEST_GLOB and PENDING reasons; the header lists the remaining row kinds. Tests: new brain-context-load case loads the shipped investigate and office-hours queries against a configured root and proves a file only under ~/.gstack is not read. --- design-consultation/SKILL.md.tmpl | 2 +- design-shotgun/SKILL.md.tmpl | 2 +- investigate/SKILL.md.tmpl | 4 +-- office-hours/SKILL.md.tmpl | 6 ++-- plan-ceo-review/SKILL.md.tmpl | 2 +- retro/SKILL.md.tmpl | 4 +-- test/gstack-brain-context-load.test.ts | 45 ++++++++++++++++++++++++++ test/instruction-facts.test.ts | 18 +++-------- 8 files changed, 59 insertions(+), 24 deletions(-) diff --git a/design-consultation/SKILL.md.tmpl b/design-consultation/SKILL.md.tmpl index a48b49a21..5052941d0 100644 --- a/design-consultation/SKILL.md.tmpl +++ b/design-consultation/SKILL.md.tmpl @@ -33,7 +33,7 @@ gbrain: render_as: "## Existing DESIGN.md (if any)" - id: prior-design-decisions kind: filesystem - glob: "~/.gstack/projects/{repo_slug}/*-design-*.md" + glob: "{gstack_state_root}/projects/{repo_slug}/*-design-*.md" sort: mtime_desc limit: 3 render_as: "## Prior design decisions for this project" diff --git a/design-shotgun/SKILL.md.tmpl b/design-shotgun/SKILL.md.tmpl index 16c7a8ccb..22bc077b3 100644 --- a/design-shotgun/SKILL.md.tmpl +++ b/design-shotgun/SKILL.md.tmpl @@ -36,7 +36,7 @@ gbrain: render_as: "## DESIGN.md (project design system)" - id: recent-design-docs kind: filesystem - glob: "~/.gstack/projects/{repo_slug}/*-design-*.md" + glob: "{gstack_state_root}/projects/{repo_slug}/*-design-*.md" sort: mtime_desc limit: 3 render_as: "## Recent design docs" diff --git a/investigate/SKILL.md.tmpl b/investigate/SKILL.md.tmpl index eb0846c24..ab57e5fcd 100644 --- a/investigate/SKILL.md.tmpl +++ b/investigate/SKILL.md.tmpl @@ -51,12 +51,12 @@ gbrain: render_as: "## Prior investigations in this repo" - id: project-learnings kind: filesystem - glob: "~/.gstack/projects/{repo_slug}/learnings.jsonl" + glob: "{gstack_state_root}/projects/{repo_slug}/learnings.jsonl" tail: 10 render_as: "## Recent learnings (patterns + pitfalls)" - id: recent-eureka kind: filesystem - glob: "~/.gstack/analytics/eureka.jsonl" + glob: "{gstack_state_root}/analytics/eureka.jsonl" tail: 5 render_as: "## Recent eureka moments (cross-project)" --- diff --git a/office-hours/SKILL.md.tmpl b/office-hours/SKILL.md.tmpl index 1300ce7a0..c682ee1b8 100644 --- a/office-hours/SKILL.md.tmpl +++ b/office-hours/SKILL.md.tmpl @@ -41,17 +41,17 @@ gbrain: render_as: "## Prior office-hours sessions in this repo" - id: builder-profile kind: filesystem - glob: "~/.gstack/developer-profile.json" + glob: "{gstack_state_root}/developer-profile.json" render_as: "## Your builder profile snapshot" - id: design-doc-history kind: filesystem - glob: "~/.gstack/projects/{repo_slug}/*-design-*.md" + glob: "{gstack_state_root}/projects/{repo_slug}/*-design-*.md" sort: mtime_desc limit: 3 render_as: "## Recent design docs for this project" - id: prior-eureka kind: filesystem - glob: "~/.gstack/analytics/eureka.jsonl" + glob: "{gstack_state_root}/analytics/eureka.jsonl" tail: 5 render_as: "## Recent eureka moments" --- diff --git a/plan-ceo-review/SKILL.md.tmpl b/plan-ceo-review/SKILL.md.tmpl index 878bb35eb..72eae1195 100644 --- a/plan-ceo-review/SKILL.md.tmpl +++ b/plan-ceo-review/SKILL.md.tmpl @@ -36,7 +36,7 @@ gbrain: render_as: "## Prior CEO plans for this project" - id: recent-design-docs kind: filesystem - glob: "~/.gstack/projects/{repo_slug}/*-design-*.md" + glob: "{gstack_state_root}/projects/{repo_slug}/*-design-*.md" sort: mtime_desc limit: 3 render_as: "## Recent design docs for this project" diff --git a/retro/SKILL.md.tmpl b/retro/SKILL.md.tmpl index fea06db3b..2fb207723 100644 --- a/retro/SKILL.md.tmpl +++ b/retro/SKILL.md.tmpl @@ -30,12 +30,12 @@ gbrain: render_as: "## Prior retros for this project" - id: recent-timeline kind: filesystem - glob: "~/.gstack/projects/{repo_slug}/timeline.jsonl" + glob: "{gstack_state_root}/projects/{repo_slug}/timeline.jsonl" tail: 30 render_as: "## Recent timeline events" - id: recent-learnings kind: filesystem - glob: "~/.gstack/projects/{repo_slug}/learnings.jsonl" + glob: "{gstack_state_root}/projects/{repo_slug}/learnings.jsonl" tail: 10 render_as: "## Recent learnings" --- diff --git a/test/gstack-brain-context-load.test.ts b/test/gstack-brain-context-load.test.ts index c47d31db4..9fbc49d2a 100644 --- a/test/gstack-brain-context-load.test.ts +++ b/test/gstack-brain-context-load.test.ts @@ -606,6 +606,51 @@ gbrain: } }); +describe("gstack-brain-context-load — shipped state-root manifest files read the configured root", () => { + const cases = [ + { skill: "investigate", id: "project-learnings", file: ["projects", "test-repo", "learnings.jsonl"] }, + { skill: "investigate", id: "recent-eureka", file: ["analytics", "eureka.jsonl"] }, + { skill: "office-hours", id: "design-doc-history", file: ["projects", "test-repo", "alice-main-design-20260914.md"] }, + ]; + for (const c of cases) it(`${c.skill}:${c.id} reads only the configured root`, () => { + const dir = mkdtempSync(join(tmpdir(), "gstack-state-manifest-")); + const home = join(dir, "home"); + const configured = join(dir, "configured"); + try { + const target = join(configured, ...c.file); + mkdirSync(join(target, ".."), { recursive: true }); + writeFileSync(target, "{}\n"); + mkdirSync(home, { recursive: true }); + const query = parseSkillManifest(join(import.meta.dir, "..", c.skill, "SKILL.md.tmpl"))! + .context_queries.find(item => item.id === c.id)!; + expect(query.glob!.startsWith("{gstack_state_root}/")).toBe(true); + const skillFile = join(dir, "SKILL.md"); + writeFileSync(skillFile, `--- +name: state-manifest-fixture +gbrain: + schema: 1 + context_queries: + - id: ${query.id} + kind: filesystem + glob: "${query.glob}" + render_as: "${query.render_as}" +--- +`); + const env = { HOME: home, USERPROFILE: home, GSTACK_HOME: configured, CLAUDE_PLUGIN_DATA: "", CLAUDE_PLUGIN_ROOT: "" }; + const r = runScript(["--skill-file", skillFile, "--repo", "test-repo", "--explain"], env); + expect(r.exitCode).toBe(0); + expect(r.stderr).toContain(`OK ${c.id}`); + expect(r.stdout).toContain(c.file[c.file.length - 1]!); + rmSync(target); + mkdirSync(join(home, ".gstack", ...c.file.slice(0, -1)), { recursive: true }); + writeFileSync(join(home, ".gstack", ...c.file), "{}\n"); + const legacyOnly = runScript(["--skill-file", skillFile, "--repo", "test-repo", "--explain"], env); + expect(legacyOnly.exitCode).toBe(0); + expect(legacyOnly.stderr).toContain(`SKIP ${c.id}`); + } finally { rmSync(dir, { recursive: true, force: true }); } + }); +}); + describe("gstack-brain-context-load — real gbrain CLI contract (#2883)", () => { const ROWS = [ "plans/brand-plan\\tceo-plan\\t2026-10-01\\tBrand plan", diff --git a/test/instruction-facts.test.ts b/test/instruction-facts.test.ts index 64a74e0cb..481942ad1 100644 --- a/test/instruction-facts.test.ts +++ b/test/instruction-facts.test.ts @@ -160,37 +160,27 @@ describe('/ship step references resolve to the step they mean', () => { // Every literal default-root state path in templates and resolvers. Writers // resolve $GSTACK_STATE_ROOT (docs/state-root.md); a literal ~/.gstack path -// only matches them when the state root is the default. Rows are either -// user-facing descriptions, manifest/legacy forms read literally, or -// conversions still pending (tracked in TODOS.md). New hits fail. +// only matches them when the state root is the default. Rows are user-facing +// descriptions, source comments, or readers that must match a writer outside +// the state root. Manifest globs use the `{gstack_state_root}/` prefix. New +// hits fail. const STATE_ROOT_LITERAL = /~\/\.gstack\/(?:projects|analytics)\//g; const RATCHET_ALLOWLIST = JSON.parse(read('test/state-root-ratchet.allowlist.json')) as Array<{ path: string; match: string; reason: string }>; const readinessEvalReason = RATCHET_ALLOWLIST.find(entry => entry.path === 'land-and-deploy/sections/readiness-gate.md.tmpl')!.reason; -const MANIFEST_GLOB = 'gbrain context_queries manifest glob: bin/gstack-brain-context-load.ts reads the legacy `~` form literally (default state root only); `{gstack_state_root}/` is the state-root form. Conversion pending (TODOS.md: state-root literals in templates)'; const DESCRIPTION = 'user-facing description of where the data lives; no command reads or writes this literal'; -const PENDING = 'agent reads or writes this literal default-root path; it diverges from $GSTACK_STATE_ROOT writers under a non-default state root. Conversion pending (TODOS.md: state-root literals in templates)'; const SOURCE_COMMENT = 'source comment, not rendered into any skill'; const STATE_ROOT_ALLOWLIST: Array<{ file: string; match: string; reason: string }> = [ { file: 'autoplan/SKILL.md.tmpl', match: 'test plan on disk at ~/.gstack/projects/$SLUG/', reason: DESCRIPTION }, { file: 'careful/SKILL.md.tmpl', match: '`~/.gstack/projects//careful-patterns.txt` (per-project)', reason: DESCRIPTION }, - { file: 'design-consultation/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/*-design-*.md"', reason: MANIFEST_GLOB }, - { file: 'design-shotgun/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/*-design-*.md"', reason: MANIFEST_GLOB }, { file: 'design-shotgun/SKILL.md.tmpl', match: 'v1 schema at `~/.gstack/projects/$SLUG/taste-profile.json`', reason: DESCRIPTION }, - { file: 'investigate/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/learnings.jsonl"', reason: MANIFEST_GLOB }, - { file: 'investigate/SKILL.md.tmpl', match: 'glob: "~/.gstack/analytics/eureka.jsonl"', reason: MANIFEST_GLOB }, { file: 'land-and-deploy/sections/readiness-gate.md.tmpl', match: 'eval store (`~/.gstack/projects//evals/`', reason: readinessEvalReason }, { file: 'land-and-deploy/sections/readiness-gate.md.tmpl', match: 'EVAL_DIR=~/.gstack/projects/$SLUG/evals', reason: readinessEvalReason }, - { file: 'office-hours/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/*-design-*.md"', reason: MANIFEST_GLOB }, - { file: 'office-hours/SKILL.md.tmpl', match: 'glob: "~/.gstack/analytics/eureka.jsonl"', reason: MANIFEST_GLOB }, { file: 'office-hours/SKILL.md.tmpl', match: "see each other's design docs in `~/.gstack/projects/`", reason: DESCRIPTION }, { file: 'office-hours/sections/design-and-handoff.md.tmpl', match: 'The design doc at `~/.gstack/projects/` is automatically discoverable', reason: DESCRIPTION }, - { file: 'plan-ceo-review/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/*-design-*.md"', reason: MANIFEST_GLOB }, { file: 'plan-ceo-review/sections/review-sections.md.tmpl', match: 'Keep in `~/.gstack/projects/` only (local, personal reference)', reason: DESCRIPTION }, { file: 'plan-tune/SKILL.md.tmpl', match: 'Logs stay local (`~/.gstack/projects//question-log.jsonl`)', reason: DESCRIPTION }, { file: 'plan-tune/SKILL.md.tmpl', match: '`~/.gstack/projects//question-log.jsonl` — nothing leaves your', reason: DESCRIPTION }, - { file: 'retro/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/timeline.jsonl"', reason: MANIFEST_GLOB }, - { file: 'retro/SKILL.md.tmpl', match: 'glob: "~/.gstack/projects/{repo_slug}/learnings.jsonl"', reason: MANIFEST_GLOB }, { file: 'scripts/resolvers/learnings.ts', match: '* Learnings are stored per-project at ~/.gstack/projects/{slug}/learnings.jsonl', reason: SOURCE_COMMENT }, { file: 'scripts/resolvers/preamble.ts', match: 'local JSONL append to ~/.gstack/analytics/ (inline, inspectable)', reason: SOURCE_COMMENT }, ]; From 4d371a98ade04f68a047609428f294e56e3d9fde Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 3 Oct 2026 02:21:06 +0000 Subject: [PATCH 10/10] chore: regenerate SKILL.md and context budget after manifest state-root globs --- design-consultation/SKILL.md | 2 +- design-shotgun/SKILL.md | 2 +- investigate/SKILL.md | 4 ++-- office-hours/SKILL.md | 6 +++--- plan-ceo-review/SKILL.md | 2 +- retro/SKILL.md | 4 ++-- test/fixtures/context-budget.json | 14 +++++++------- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/design-consultation/SKILL.md b/design-consultation/SKILL.md index 3cd1673c8..7f71fb9ed 100644 --- a/design-consultation/SKILL.md +++ b/design-consultation/SKILL.md @@ -26,7 +26,7 @@ gbrain: render_as: "## Existing DESIGN.md (if any)" - id: prior-design-decisions kind: filesystem - glob: "~/.gstack/projects/{repo_slug}/*-design-*.md" + glob: "{gstack_state_root}/projects/{repo_slug}/*-design-*.md" sort: mtime_desc limit: 3 render_as: "## Prior design decisions for this project" diff --git a/design-shotgun/SKILL.md b/design-shotgun/SKILL.md index 24b3b1dbf..05607f5e7 100644 --- a/design-shotgun/SKILL.md +++ b/design-shotgun/SKILL.md @@ -30,7 +30,7 @@ gbrain: render_as: "## DESIGN.md (project design system)" - id: recent-design-docs kind: filesystem - glob: "~/.gstack/projects/{repo_slug}/*-design-*.md" + glob: "{gstack_state_root}/projects/{repo_slug}/*-design-*.md" sort: mtime_desc limit: 3 render_as: "## Recent design docs" diff --git a/investigate/SKILL.md b/investigate/SKILL.md index 7a9a05f4f..18f429ad7 100644 --- a/investigate/SKILL.md +++ b/investigate/SKILL.md @@ -44,12 +44,12 @@ gbrain: render_as: "## Prior investigations in this repo" - id: project-learnings kind: filesystem - glob: "~/.gstack/projects/{repo_slug}/learnings.jsonl" + glob: "{gstack_state_root}/projects/{repo_slug}/learnings.jsonl" tail: 10 render_as: "## Recent learnings (patterns + pitfalls)" - id: recent-eureka kind: filesystem - glob: "~/.gstack/analytics/eureka.jsonl" + glob: "{gstack_state_root}/analytics/eureka.jsonl" tail: 5 render_as: "## Recent eureka moments (cross-project)" --- diff --git a/office-hours/SKILL.md b/office-hours/SKILL.md index 0de969e06..2d6b8ae39 100644 --- a/office-hours/SKILL.md +++ b/office-hours/SKILL.md @@ -30,17 +30,17 @@ gbrain: render_as: "## Prior office-hours sessions in this repo" - id: builder-profile kind: filesystem - glob: "~/.gstack/developer-profile.json" + glob: "{gstack_state_root}/developer-profile.json" render_as: "## Your builder profile snapshot" - id: design-doc-history kind: filesystem - glob: "~/.gstack/projects/{repo_slug}/*-design-*.md" + glob: "{gstack_state_root}/projects/{repo_slug}/*-design-*.md" sort: mtime_desc limit: 3 render_as: "## Recent design docs for this project" - id: prior-eureka kind: filesystem - glob: "~/.gstack/analytics/eureka.jsonl" + glob: "{gstack_state_root}/analytics/eureka.jsonl" tail: 5 render_as: "## Recent eureka moments" --- diff --git a/plan-ceo-review/SKILL.md b/plan-ceo-review/SKILL.md index 61a376067..8f2be845f 100644 --- a/plan-ceo-review/SKILL.md +++ b/plan-ceo-review/SKILL.md @@ -26,7 +26,7 @@ gbrain: render_as: "## Prior CEO plans for this project" - id: recent-design-docs kind: filesystem - glob: "~/.gstack/projects/{repo_slug}/*-design-*.md" + glob: "{gstack_state_root}/projects/{repo_slug}/*-design-*.md" sort: mtime_desc limit: 3 render_as: "## Recent design docs for this project" diff --git a/retro/SKILL.md b/retro/SKILL.md index 00d62f6c9..141bea3cd 100644 --- a/retro/SKILL.md +++ b/retro/SKILL.md @@ -25,12 +25,12 @@ gbrain: render_as: "## Prior retros for this project" - id: recent-timeline kind: filesystem - glob: "~/.gstack/projects/{repo_slug}/timeline.jsonl" + glob: "{gstack_state_root}/projects/{repo_slug}/timeline.jsonl" tail: 30 render_as: "## Recent timeline events" - id: recent-learnings kind: filesystem - glob: "~/.gstack/projects/{repo_slug}/learnings.jsonl" + glob: "{gstack_state_root}/projects/{repo_slug}/learnings.jsonl" tail: 10 render_as: "## Recent learnings" --- diff --git a/test/fixtures/context-budget.json b/test/fixtures/context-budget.json index 5254cdc48..8ba9f0336 100644 --- a/test/fixtures/context-budget.json +++ b/test/fixtures/context-budget.json @@ -1,6 +1,6 @@ { "_comment": "Context-budget ratchet ceilings (~tokens). Regenerate: bun test/helpers/capture-context-budget.ts. Headroom: alwaysOnTotal x1.05, eagerPerInvocation x1.1. Graded by test/context-budget-ratchet.test.ts via lib/context-bill.ts checkBudget.", - "alwaysOnTotal": 6814, + "alwaysOnTotal": 6840, "eagerPerInvocation": { "autoplan": 17212, "benchmark": 7673, @@ -13,10 +13,10 @@ "context-restore": 10492, "context-save": 10284, "cso": 4700, - "design-consultation": 15629, + "design-consultation": 15631, "design-html": 14324, "design-review": 34521, - "design-shotgun": 13876, + "design-shotgun": 13879, "deslop-shared-libs": 3419, "devex-review": 19738, "diagram": 4267, @@ -27,7 +27,7 @@ "gstack-upgrade": 4711, "guard": 939, "health": 11798, - "investigate": 12436, + "investigate": 12441, "ios-clean": 8589, "ios-design-review": 8774, "ios-fix": 8478, @@ -37,21 +37,21 @@ "landing-report": 9301, "learn": 8996, "make-pdf": 5233, - "office-hours": 22616, + "office-hours": 22624, "open-gstack-browser": 4840, "openclaw/skills/gstack-openclaw-ceo-review": 2764, "openclaw/skills/gstack-openclaw-investigate": 1429, "openclaw/skills/gstack-openclaw-office-hours": 4433, "openclaw/skills/gstack-openclaw-retro": 2542, "pair-agent": 11399, - "plan-ceo-review": 21044, + "plan-ceo-review": 21047, "plan-design-review": 20519, "plan-devex-review": 17906, "plan-eng-review": 13521, "plan-tune": 14734, "qa": 13570, "qa-only": 11742, - "retro": 19033, + "retro": 19038, "review": 19562, "scrape": 6876, "setup-browser-cookies": 3497,