diff --git a/office-hours/SKILL.md.tmpl b/office-hours/SKILL.md.tmpl index c682ee1b8..533578cfc 100644 --- a/office-hours/SKILL.md.tmpl +++ b/office-hours/SKILL.md.tmpl @@ -299,7 +299,7 @@ Count the signals. You'll use this count in Phase 6 to determine which tier of c After counting signals, append a session entry to the builder profile. This is the single source of truth for all closing state (tier, resource dedup, journey tracking). The `gstack-developer-profile --log-session` binary handles its own directory creation -and writes via atomic mktemp+mv to `~/.gstack/developer-profile.json`. +and writes via atomic mktemp+mv to `$GSTACK_STATE_ROOT/developer-profile.json`. Append one JSON line with these fields (substitute actual values from this session): - `date`: current ISO 8601 timestamp diff --git a/plan-tune/SKILL.md.tmpl b/plan-tune/SKILL.md.tmpl index d89bee65b..ffd9055fe 100644 --- a/plan-tune/SKILL.md.tmpl +++ b/plan-tune/SKILL.md.tmpl @@ -62,11 +62,11 @@ and so accumulated free-text answers get dream-cycled into actionable proposals. Each gate is guarded by a marker so the user is prompted at most once per choice. 1. **Consent gate.** If `question_tuning` is `false` AND - `~/.gstack/.question-tuning-prompted` is missing → run `Consent + opt-in` + `$GSTACK_STATE_ROOT/.question-tuning-prompted` is missing → run `Consent + opt-in` below. Honor the answer with a marker write either way; do not re-prompt. 2. **Setup gate.** If `question_tuning` is `true` AND - `~/.gstack/developer-profile.json`'s `declared` object is empty AND - `~/.gstack/.declared-setup-prompted` is missing → run `5-Q setup` below. + `$GSTACK_STATE_ROOT/developer-profile.json`'s `declared` object is empty AND + `$GSTACK_STATE_ROOT/.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_STATE_ROOT/projects//distillation-proposals.json` exists AND has @@ -88,7 +88,7 @@ When no implicit gate fires, route by user intent: 9. **"Dream cycle" / "distill" / "what have I been free-texting"** → run `Dream cycle distill` below (triggers `gstack-distill-free-text`). 10. **"Turn it off" / "disable"** → `~/.claude/skills/gstack/bin/gstack-config set question_tuning false` -11. **"Turn it on" / "enable"** → `~/.claude/skills/gstack/bin/gstack-config set question_tuning true && touch ~/.gstack/.question-tuning-prompted` +11. **"Turn it on" / "enable"** → `~/.claude/skills/gstack/bin/gstack-config set question_tuning true && eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}"; touch "$GSTACK_STATE_ROOT"/.question-tuning-prompted` 12. **Clear ambiguity** — if you can't tell what the user wants, ask plainly: "Do you want to (a) see your profile, (b) review recent questions, (c) set a preference, (d) update your declared profile, (e) run the dream cycle, @@ -103,7 +103,7 @@ Power-user shortcuts (one-word invocations) — handle these too: ## Consent + opt-in **When this fires.** Step 0's consent gate: `question_tuning` is `false` AND -`~/.gstack/.question-tuning-prompted` is missing. The user has never been +`$GSTACK_STATE_ROOT/.question-tuning-prompted` is missing. The user has never been asked. **Privacy note.** gstack defaults `question_tuning` to `false` for every user. @@ -177,7 +177,7 @@ explicit. - Right after the consent prompt above accepts option A. - Standalone via Step 0's setup gate: `question_tuning` is already `true` (user opted in via gstack-config or earlier `/plan-tune enable`) AND - `declared` is empty AND `~/.gstack/.declared-setup-prompted` is missing. + `declared` is empty AND `$GSTACK_STATE_ROOT/.declared-setup-prompted` is missing. This catches users who set `question_tuning: true` directly without running the wizard. @@ -213,7 +213,7 @@ explicit. After each answer, map A/B/C to the numeric value and save the declared dimension. Write each declaration directly into - `~/.gstack/developer-profile.json` under `declared.{dimension}`: + `$GSTACK_STATE_ROOT/developer-profile.json` under `declared.{dimension}`: ```bash # Ensure profile exists diff --git a/retro/SKILL.md.tmpl b/retro/SKILL.md.tmpl index 2fb207723..4f91f0da5 100644 --- a/retro/SKILL.md.tmpl +++ b/retro/SKILL.md.tmpl @@ -155,8 +155,8 @@ Also check `RETRO_REF`: if it is not `origin/` (local-only repo, missin **Optional inputs** (Read each file the script marks `present`): -- `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. +- `RETRO_CONTEXT: present` → Read the `retro-context.md` path that line printed. 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 the `greptile-history.md` path that line printed. 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 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. @@ -414,7 +414,7 @@ Use the Write tool to save the JSON file with this schema: } ``` -**Note:** Only include the `greptile` field if `~/.gstack/greptile-history.md` exists and has entries within the time window. Only include the `backlog` field if `TODOS.md` exists. Only include the `test_health` field if test files were found (`TEST_FILES_TOTAL` > 0). If any has no data, omit the field entirely. +**Note:** Only include the `greptile` field if `greptile-history.md` (the path `GREPTILE_HISTORY` printed) exists and has entries within the time window. Only include the `backlog` field if `TODOS.md` exists. Only include the `test_health` field if test files were found (`TEST_FILES_TOTAL` > 0). If any has no data, omit the field entirely. Include test health data in the JSON when test files exist: ```json diff --git a/test/skill-validation.test.ts b/test/skill-validation.test.ts index 9561d4433..299416ba8 100644 --- a/test/skill-validation.test.ts +++ b/test/skill-validation.test.ts @@ -471,7 +471,8 @@ describe('Cross-skill path consistency', () => { test('retro/SKILL.md reads global greptile-history (not per-project)', () => { const content = fs.readFileSync(path.join(ROOT, 'retro', 'SKILL.md'), 'utf-8'); - expect(content).toContain('~/.gstack/greptile-history.md'); + expect(content).toContain('the path `GREPTILE_HISTORY` printed'); + expect(fs.readFileSync(path.join(ROOT, 'bin', 'gstack-retro-metrics'), 'utf-8')).toContain('$_GH/greptile-history.md'); // Should NOT reference per-project path for reads expect(content).not.toContain('$REMOTE_SLUG/greptile-history.md'); });