From 66f27cfcc55f22981727aee116a862da2eb4b065 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Wed, 27 May 2026 07:52:03 -0700 Subject: [PATCH] feat(plan-tune): SKILL.md surfaces for cathedral T13 Plan-tune cathedral T13. Rewires plan-tune/SKILL.md.tmpl to expose the new cathedral surfaces: Step 0 routing: - Implicit gate #3 (dream-cycle): fires when distillation-proposals.json has unapplied proposals. Marker is per-proposal applied_at so re-firing naturally skips already-handled items. - Added user-intent route for "dream cycle" / "distill" / "what have I been free-texting". - Power-user shortcuts: distill, dream, audit. Stats: - Host-aware source breakdown (SOURCE_HOOK, SOURCE_AGENT, SOURCE_AUTO_DECIDED, SOURCE_CODEX_IMPORT_*, SOURCE_AUQ_OTHER). - MARKED percentage so D18 progressive-markers progress is visible. - Distill cost-to-date via gstack-distill-free-text --status. Recent auto-decisions: - Last 10 source=auto-decided events with question_id + user_choice. Lets the user spot-check enforcement and flip via always-ask. Audit unmarked questions: - Top N hash-only ids by frequency. Surfaces next candidates for the D18 marker retrofit. Dream cycle review + manual distill: - Walks unapplied proposals via AskUserQuestion (one per call), routes accepts through gstack-distill-apply with --gbrain-published flag. Skill template invokes mcp__gbrain__put_page when MCP is available; local file remains source-of-truth. Regenerated SKILL.md via `bun run gen:skill-docs`. All 60 plan-tune tests still green. Co-Authored-By: Claude Opus 4.7 (1M context) --- plan-tune/SKILL.md | 227 +++++++++++++++++++++++++++++++++++++--- plan-tune/SKILL.md.tmpl | 227 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 426 insertions(+), 28 deletions(-) diff --git a/plan-tune/SKILL.md b/plan-tune/SKILL.md index dc845fe93..17240a591 100644 --- a/plan-tune/SKILL.md +++ b/plan-tune/SKILL.md @@ -747,8 +747,9 @@ Canonical reference: `docs/designs/PLAN_TUNING_V0.md`. Read the user's message. Route based on plain-English intent, not keywords. **Implicit gates run first** (before user-intent routing). These exist so first-time -users see the consent prompt and so explicit opt-ins eventually run the 5-Q setup. -Each gate is guarded by a marker file so the user is asked at most once. +users see the consent prompt, so explicit opt-ins eventually run the 5-Q setup, +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` @@ -757,26 +758,35 @@ Each gate is guarded by a marker file so the user is asked at most once. `~/.gstack/developer-profile.json`'s `declared` object is empty AND `~/.gstack/.declared-setup-prompted` is missing → run `5-Q setup` below. Touch the marker after setup completes OR is declined. +3. **Dream-cycle gate (Layer 8 / cathedral T10/T11).** If + `~/.gstack/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. -When neither implicit gate fires, route by user intent: +When no implicit gate fires, route by user intent: -3. **"Show my profile" / "what do you know about me" / "show my vibe"** → +4. **"Show my profile" / "what do you know about me" / "show my vibe"** → run `Inspect profile`. -4. **"Review questions" / "what have I been asked" / "show recent"** → +5. **"Review questions" / "what have I been asked" / "show recent"** → run `Review question log`. -5. **"Stop asking me about X" / "never ask about Y" / "tune: ..."** → +6. **"Stop asking me about X" / "never ask about Y" / "tune: ..."** → run `Set a preference`. -6. **"Update my profile" / "I'm more boil-the-ocean than that" / "I've changed +7. **"Update my profile" / "I'm more boil-the-ocean than that" / "I've changed my mind"** → run `Edit declared profile` (confirm before writing). -7. **"Show the gap" / "how far off is my profile"** → run `Show gap`. -8. **"Turn it off" / "disable"** → `~/.claude/skills/gstack/bin/gstack-config set question_tuning false` -9. **"Turn it on" / "enable"** → `~/.claude/skills/gstack/bin/gstack-config set question_tuning true && touch ~/.gstack/.question-tuning-prompted` -10. **Clear ambiguity** — if you can't tell what the user wants, ask plainly: +8. **"Show the gap" / "how far off is my profile"** → run `Show gap`. +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` +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, or (e) turn it off?" + a preference, (d) update your declared profile, (e) run the dream cycle, + or (f) turn it off?" Power-user shortcuts (one-word invocations) — handle these too: -`profile`, `vibe`, `gap`, `stats`, `review`, `enable`, `disable`, `setup`. +`profile`, `vibe`, `gap`, `stats`, `review`, `enable`, `disable`, `setup`, +`distill`, `dream`, `audit`. --- @@ -1106,12 +1116,37 @@ the user decides whether declared is wrong or behavior is wrong. ## Stats +Cathedral T13 surfaces: host-aware breakdown (claude hook vs codex import +vs agent-enriched), marked vs hash-only, auto-decided count, and dream +cycle cost-to-date. + ```bash ~/.claude/skills/gstack/bin/gstack-question-preference --stats eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" eval "$(~/.claude/skills/gstack/bin/gstack-paths)" _LOG="$GSTACK_STATE_ROOT/projects/$SLUG/question-log.jsonl" -[ -f "$_LOG" ] && echo "TOTAL_LOGGED: $(wc -l < "$_LOG" | tr -d ' ')" || echo "TOTAL_LOGGED: 0" +if [ -f "$_LOG" ]; then + bun -e " + const lines = require('fs').readFileSync('$_LOG','utf-8').trim().split('\n').filter(Boolean); + const events = []; + for (const l of lines) { try { events.push(JSON.parse(l)); } catch {} } + const total = events.length; + const bySource = {}; + let marked = 0; + for (const e of events) { + const src = e.source || 'agent'; + bySource[src] = (bySource[src] || 0) + 1; + if (e.question_id && !e.question_id.startsWith('hook-')) marked++; + } + console.log('TOTAL_LOGGED: ' + total); + console.log('MARKED: ' + marked + ' (' + (total ? Math.round(100*marked/total) : 0) + '%)'); + for (const s of Object.keys(bySource).sort()) { + console.log('SOURCE_' + s.toUpperCase().replace(/-/g,'_') + ': ' + bySource[s]); + } + " +else + echo 'TOTAL_LOGGED: 0' +fi ~/.claude/skills/gstack/bin/gstack-developer-profile --profile | bun -e " const p = JSON.parse(await Bun.stdin.text()); const d = p.inferred?.diversity || {}; @@ -1120,10 +1155,174 @@ _LOG="$GSTACK_STATE_ROOT/projects/$SLUG/question-log.jsonl" console.log('DAYS_SPAN: ' + (d.days_span ?? 0)); console.log('CALIBRATED: ' + (p.inferred?.sample_size >= 20 && d.skills_covered >= 3 && d.question_ids_covered >= 8 && d.days_span >= 7)); " +echo '---DISTILL---' +~/.claude/skills/gstack/bin/gstack-distill-free-text --status ``` Present as a compact summary with plain-English calibration status ("5 more events across 2 more skills and you'll be calibrated" or "you're calibrated"). +Surface the source breakdown so the user can see capture is real (Codex +correction — without source columns, the cathedral's "before:0 / after:>0" +claim is invisible). + +--- + +## Recent auto-decisions + +Show the last 10 questions where the PreToolUse hook auto-decided (source= +`auto-decided` in the log). Lets the user spot-check enforcement and flip +any that misfired via `always-ask`. + +```bash +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" +eval "$(~/.claude/skills/gstack/bin/gstack-paths)" +_LOG="$GSTACK_STATE_ROOT/projects/$SLUG/question-log.jsonl" +[ ! -f "$_LOG" ] && echo 'NO_LOG' || bun -e " + const lines = require('fs').readFileSync('$_LOG','utf-8').trim().split('\n').filter(Boolean); + const auto = []; + for (const l of lines) { + try { const e = JSON.parse(l); if (e.source === 'auto-decided') auto.push(e); } catch {} + } + const recent = auto.slice(-10).reverse(); + if (!recent.length) { console.log('(no auto-decisions yet)'); process.exit(0); } + for (const r of recent) { + console.log(r.ts + ' ' + r.question_id + ' → ' + r.user_choice); + console.log(' ' + (r.question_summary || '')); + } +" +``` + +If any look wrong, offer: "Want to flip `` to `always-ask`?" +Run `gstack-question-preference --write '{"question_id":"","preference": +"always-ask","source":"plan-tune"}'` after Y. + +--- + +## Audit unmarked questions + +Top N hash-only question_ids by frequency. These are AUQ fires the cathedral +hook captured but cannot enforce against (no `` marker in +the skill template — D18 progressive markers). Surfacing them drives marker +adoption: high-traffic unmarked questions are the next candidates to retrofit. + +```bash +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" +eval "$(~/.claude/skills/gstack/bin/gstack-paths)" +_LOG="$GSTACK_STATE_ROOT/projects/$SLUG/question-log.jsonl" +[ ! -f "$_LOG" ] && echo 'NO_LOG' || bun -e " + const lines = require('fs').readFileSync('$_LOG','utf-8').trim().split('\n').filter(Boolean); + const counts = {}; + const summaries = {}; + for (const l of lines) { + try { + const e = JSON.parse(l); + if (e.question_id && e.question_id.startsWith('hook-')) { + counts[e.question_id] = (counts[e.question_id] || 0) + 1; + summaries[e.question_id] = e.question_summary || ''; + } + } catch {} + } + const rows = Object.entries(counts).sort((a,b) => b[1] - a[1]).slice(0, 10); + if (!rows.length) { console.log('(no unmarked questions — coverage is 100%)'); process.exit(0); } + for (const [id, n] of rows) { + console.log(n + 'x ' + id); + console.log(' ' + summaries[id]); + } +" +``` + +For each row, suggest where the marker should land (look up the skill from +the summary's wording, e.g. "Bundle this fix..." likely lives in +`ship/SKILL.md.tmpl`). Don't write markers without user approval — adding +markers changes which AUQ fires can be auto-decided, which is a substrate +expansion. + +--- + +## Dream cycle review + +**When this fires.** Step 0's dream-cycle gate: `distillation-proposals.json` +has at least one proposal with `applied_at` missing. Or the user explicitly +invokes via `/plan-tune distill` / `dream`. + +**Flow:** + +1. Show the proposals: + ```bash + ~/.claude/skills/gstack/bin/gstack-distill-apply --list + ``` + +2. For each unapplied proposal, present it as a numbered item and use + AskUserQuestion (one per call, per skill convention). Show: + - Kind (`preference` / `declared-nudge` / `memory-nugget`) + - Confidence + rationale + - The source quotes verbatim (proves user-origin) + - What applying does (which file/key/dim changes) + +3. **On accept** (Y): apply via the bin. The skill also publishes the + nugget to gbrain when configured. + + For `memory-nugget`: + ```bash + # If gbrain is configured, mirror via MCP first. + # (Pseudo — actual gbrain call happens at the agent layer via + # mcp__gbrain__put_page; the bin records the published flag.) + ~/.claude/skills/gstack/bin/gstack-distill-apply --proposal N --gbrain-published true|false + ``` + + For `preference`: + ```bash + ~/.claude/skills/gstack/bin/gstack-distill-apply --proposal N + ``` + + For `declared-nudge`: + ```bash + # Same bin; updates developer-profile.json declared dim with the + # clamped delta. + ~/.claude/skills/gstack/bin/gstack-distill-apply --proposal N + ``` + +4. **On decline**: skip without marking. User can re-decide later (the + proposal stays in the file). To dismiss permanently, manually clear: + `gstack-distill-apply --proposal N --dismiss` (not implemented in T11; + for now, regenerate via next distill run with corrected free-text). + +5. **gbrain integration.** When `mcp__gbrain__*` tools are available in + this session: + - On `memory-nugget` apply: `mcp__gbrain__put_page` with the nugget + + `mcp__gbrain__extract_facts` + `mcp__gbrain__add_tag` per the cathedral + plan D9 routing. Then pass `--gbrain-published true` to the bin so + the proposals file records the mirror. + - When gbrain isn't configured (no MCP tools), the bin's local file + write is the durable source-of-truth and the PreToolUse hook reads it + via Layer 8 memory injection. + +--- + +## Dream cycle distill (manual trigger) + +**When this fires.** The user invokes `/plan-tune distill` / `dream` / +`distill` / `dream cycle`. Auto-triggered version lives in Step 0 gate #3. + +**Flow:** + +1. Run distill: + ```bash + ~/.claude/skills/gstack/bin/gstack-distill-free-text + ``` + +2. If `RATE_CAPPED`: tell the user "You've hit today's 3 distills/day cap. + Run again tomorrow, or `/plan-tune stats` for run history." +3. If `NO_FREE_TEXT`: tell the user "No free-text answers since the last + distill. Keep using gstack — `Other` responses on AskUserQuestion feed + this loop." +4. If success: print the proposals count + estimated cost, then route into + `Dream cycle review` above for the user to approve each. + +For background mode (e.g., the user wants to keep working): +```bash +~/.claude/skills/gstack/bin/gstack-distill-free-text --background +``` --- diff --git a/plan-tune/SKILL.md.tmpl b/plan-tune/SKILL.md.tmpl index 2d71dffe9..dc1214d4c 100644 --- a/plan-tune/SKILL.md.tmpl +++ b/plan-tune/SKILL.md.tmpl @@ -55,8 +55,9 @@ Canonical reference: `docs/designs/PLAN_TUNING_V0.md`. Read the user's message. Route based on plain-English intent, not keywords. **Implicit gates run first** (before user-intent routing). These exist so first-time -users see the consent prompt and so explicit opt-ins eventually run the 5-Q setup. -Each gate is guarded by a marker file so the user is asked at most once. +users see the consent prompt, so explicit opt-ins eventually run the 5-Q setup, +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` @@ -65,26 +66,35 @@ Each gate is guarded by a marker file so the user is asked at most once. `~/.gstack/developer-profile.json`'s `declared` object is empty AND `~/.gstack/.declared-setup-prompted` is missing → run `5-Q setup` below. Touch the marker after setup completes OR is declined. +3. **Dream-cycle gate (Layer 8 / cathedral T10/T11).** If + `~/.gstack/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. -When neither implicit gate fires, route by user intent: +When no implicit gate fires, route by user intent: -3. **"Show my profile" / "what do you know about me" / "show my vibe"** → +4. **"Show my profile" / "what do you know about me" / "show my vibe"** → run `Inspect profile`. -4. **"Review questions" / "what have I been asked" / "show recent"** → +5. **"Review questions" / "what have I been asked" / "show recent"** → run `Review question log`. -5. **"Stop asking me about X" / "never ask about Y" / "tune: ..."** → +6. **"Stop asking me about X" / "never ask about Y" / "tune: ..."** → run `Set a preference`. -6. **"Update my profile" / "I'm more boil-the-ocean than that" / "I've changed +7. **"Update my profile" / "I'm more boil-the-ocean than that" / "I've changed my mind"** → run `Edit declared profile` (confirm before writing). -7. **"Show the gap" / "how far off is my profile"** → run `Show gap`. -8. **"Turn it off" / "disable"** → `~/.claude/skills/gstack/bin/gstack-config set question_tuning false` -9. **"Turn it on" / "enable"** → `~/.claude/skills/gstack/bin/gstack-config set question_tuning true && touch ~/.gstack/.question-tuning-prompted` -10. **Clear ambiguity** — if you can't tell what the user wants, ask plainly: +8. **"Show the gap" / "how far off is my profile"** → run `Show gap`. +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` +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, or (e) turn it off?" + a preference, (d) update your declared profile, (e) run the dream cycle, + or (f) turn it off?" Power-user shortcuts (one-word invocations) — handle these too: -`profile`, `vibe`, `gap`, `stats`, `review`, `enable`, `disable`, `setup`. +`profile`, `vibe`, `gap`, `stats`, `review`, `enable`, `disable`, `setup`, +`distill`, `dream`, `audit`. --- @@ -414,12 +424,37 @@ the user decides whether declared is wrong or behavior is wrong. ## Stats +Cathedral T13 surfaces: host-aware breakdown (claude hook vs codex import +vs agent-enriched), marked vs hash-only, auto-decided count, and dream +cycle cost-to-date. + ```bash ~/.claude/skills/gstack/bin/gstack-question-preference --stats eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" eval "$(~/.claude/skills/gstack/bin/gstack-paths)" _LOG="$GSTACK_STATE_ROOT/projects/$SLUG/question-log.jsonl" -[ -f "$_LOG" ] && echo "TOTAL_LOGGED: $(wc -l < "$_LOG" | tr -d ' ')" || echo "TOTAL_LOGGED: 0" +if [ -f "$_LOG" ]; then + bun -e " + const lines = require('fs').readFileSync('$_LOG','utf-8').trim().split('\n').filter(Boolean); + const events = []; + for (const l of lines) { try { events.push(JSON.parse(l)); } catch {} } + const total = events.length; + const bySource = {}; + let marked = 0; + for (const e of events) { + const src = e.source || 'agent'; + bySource[src] = (bySource[src] || 0) + 1; + if (e.question_id && !e.question_id.startsWith('hook-')) marked++; + } + console.log('TOTAL_LOGGED: ' + total); + console.log('MARKED: ' + marked + ' (' + (total ? Math.round(100*marked/total) : 0) + '%)'); + for (const s of Object.keys(bySource).sort()) { + console.log('SOURCE_' + s.toUpperCase().replace(/-/g,'_') + ': ' + bySource[s]); + } + " +else + echo 'TOTAL_LOGGED: 0' +fi ~/.claude/skills/gstack/bin/gstack-developer-profile --profile | bun -e " const p = JSON.parse(await Bun.stdin.text()); const d = p.inferred?.diversity || {}; @@ -428,10 +463,174 @@ _LOG="$GSTACK_STATE_ROOT/projects/$SLUG/question-log.jsonl" console.log('DAYS_SPAN: ' + (d.days_span ?? 0)); console.log('CALIBRATED: ' + (p.inferred?.sample_size >= 20 && d.skills_covered >= 3 && d.question_ids_covered >= 8 && d.days_span >= 7)); " +echo '---DISTILL---' +~/.claude/skills/gstack/bin/gstack-distill-free-text --status ``` Present as a compact summary with plain-English calibration status ("5 more events across 2 more skills and you'll be calibrated" or "you're calibrated"). +Surface the source breakdown so the user can see capture is real (Codex +correction — without source columns, the cathedral's "before:0 / after:>0" +claim is invisible). + +--- + +## Recent auto-decisions + +Show the last 10 questions where the PreToolUse hook auto-decided (source= +`auto-decided` in the log). Lets the user spot-check enforcement and flip +any that misfired via `always-ask`. + +```bash +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" +eval "$(~/.claude/skills/gstack/bin/gstack-paths)" +_LOG="$GSTACK_STATE_ROOT/projects/$SLUG/question-log.jsonl" +[ ! -f "$_LOG" ] && echo 'NO_LOG' || bun -e " + const lines = require('fs').readFileSync('$_LOG','utf-8').trim().split('\n').filter(Boolean); + const auto = []; + for (const l of lines) { + try { const e = JSON.parse(l); if (e.source === 'auto-decided') auto.push(e); } catch {} + } + const recent = auto.slice(-10).reverse(); + if (!recent.length) { console.log('(no auto-decisions yet)'); process.exit(0); } + for (const r of recent) { + console.log(r.ts + ' ' + r.question_id + ' → ' + r.user_choice); + console.log(' ' + (r.question_summary || '')); + } +" +``` + +If any look wrong, offer: "Want to flip `` to `always-ask`?" +Run `gstack-question-preference --write '{"question_id":"","preference": +"always-ask","source":"plan-tune"}'` after Y. + +--- + +## Audit unmarked questions + +Top N hash-only question_ids by frequency. These are AUQ fires the cathedral +hook captured but cannot enforce against (no `` marker in +the skill template — D18 progressive markers). Surfacing them drives marker +adoption: high-traffic unmarked questions are the next candidates to retrofit. + +```bash +eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" +eval "$(~/.claude/skills/gstack/bin/gstack-paths)" +_LOG="$GSTACK_STATE_ROOT/projects/$SLUG/question-log.jsonl" +[ ! -f "$_LOG" ] && echo 'NO_LOG' || bun -e " + const lines = require('fs').readFileSync('$_LOG','utf-8').trim().split('\n').filter(Boolean); + const counts = {}; + const summaries = {}; + for (const l of lines) { + try { + const e = JSON.parse(l); + if (e.question_id && e.question_id.startsWith('hook-')) { + counts[e.question_id] = (counts[e.question_id] || 0) + 1; + summaries[e.question_id] = e.question_summary || ''; + } + } catch {} + } + const rows = Object.entries(counts).sort((a,b) => b[1] - a[1]).slice(0, 10); + if (!rows.length) { console.log('(no unmarked questions — coverage is 100%)'); process.exit(0); } + for (const [id, n] of rows) { + console.log(n + 'x ' + id); + console.log(' ' + summaries[id]); + } +" +``` + +For each row, suggest where the marker should land (look up the skill from +the summary's wording, e.g. "Bundle this fix..." likely lives in +`ship/SKILL.md.tmpl`). Don't write markers without user approval — adding +markers changes which AUQ fires can be auto-decided, which is a substrate +expansion. + +--- + +## Dream cycle review + +**When this fires.** Step 0's dream-cycle gate: `distillation-proposals.json` +has at least one proposal with `applied_at` missing. Or the user explicitly +invokes via `/plan-tune distill` / `dream`. + +**Flow:** + +1. Show the proposals: + ```bash + ~/.claude/skills/gstack/bin/gstack-distill-apply --list + ``` + +2. For each unapplied proposal, present it as a numbered item and use + AskUserQuestion (one per call, per skill convention). Show: + - Kind (`preference` / `declared-nudge` / `memory-nugget`) + - Confidence + rationale + - The source quotes verbatim (proves user-origin) + - What applying does (which file/key/dim changes) + +3. **On accept** (Y): apply via the bin. The skill also publishes the + nugget to gbrain when configured. + + For `memory-nugget`: + ```bash + # If gbrain is configured, mirror via MCP first. + # (Pseudo — actual gbrain call happens at the agent layer via + # mcp__gbrain__put_page; the bin records the published flag.) + ~/.claude/skills/gstack/bin/gstack-distill-apply --proposal N --gbrain-published true|false + ``` + + For `preference`: + ```bash + ~/.claude/skills/gstack/bin/gstack-distill-apply --proposal N + ``` + + For `declared-nudge`: + ```bash + # Same bin; updates developer-profile.json declared dim with the + # clamped delta. + ~/.claude/skills/gstack/bin/gstack-distill-apply --proposal N + ``` + +4. **On decline**: skip without marking. User can re-decide later (the + proposal stays in the file). To dismiss permanently, manually clear: + `gstack-distill-apply --proposal N --dismiss` (not implemented in T11; + for now, regenerate via next distill run with corrected free-text). + +5. **gbrain integration.** When `mcp__gbrain__*` tools are available in + this session: + - On `memory-nugget` apply: `mcp__gbrain__put_page` with the nugget + + `mcp__gbrain__extract_facts` + `mcp__gbrain__add_tag` per the cathedral + plan D9 routing. Then pass `--gbrain-published true` to the bin so + the proposals file records the mirror. + - When gbrain isn't configured (no MCP tools), the bin's local file + write is the durable source-of-truth and the PreToolUse hook reads it + via Layer 8 memory injection. + +--- + +## Dream cycle distill (manual trigger) + +**When this fires.** The user invokes `/plan-tune distill` / `dream` / +`distill` / `dream cycle`. Auto-triggered version lives in Step 0 gate #3. + +**Flow:** + +1. Run distill: + ```bash + ~/.claude/skills/gstack/bin/gstack-distill-free-text + ``` + +2. If `RATE_CAPPED`: tell the user "You've hit today's 3 distills/day cap. + Run again tomorrow, or `/plan-tune stats` for run history." +3. If `NO_FREE_TEXT`: tell the user "No free-text answers since the last + distill. Keep using gstack — `Other` responses on AskUserQuestion feed + this loop." +4. If success: print the proposals count + estimated cost, then route into + `Dream cycle review` above for the user to approve each. + +For background mode (e.g., the user wants to keep working): +```bash +~/.claude/skills/gstack/bin/gstack-distill-free-text --background +``` ---