refactor(brain): compress GBRAIN_* resolvers, move template prose to docs/

generateGBrainContextLoad: 80 -> 115 tokens with explicit skip-header.
generateGBrainSaveResults: 500-700 -> 161 tokens per skill with the
skill metadata extracted into a typed skillSaveMap (slugPrefix + title
+ tag). Verbose prose (heredoc body, entity-stub instructions, throttle
handling, backlink protocol) moved into a new doc:
docs/gbrain-write-surfaces.md (Sections: §Context Load, §Save Template).
The agent reads the doc on-demand only when actually saving — one Read
call, cached by Claude's context.

Net per-planning-skill overhead under un-suppression drops from ~1000
tokens (naive un-suppression) to ~275 tokens (compressed). Combined
with the setup-time detection from prior commits, users WITHOUT gbrain
pay zero overhead (block suppressed at gen-time) and users WITH gbrain
pay ~275 tokens.

The /investigate special-case (data-research routing in CONTEXT_LOAD)
stays inline since it's skill-specific.

docs/gbrain-write-surfaces.md also serves as the manual-probe reference
for humans verifying live persistence + a topology summary covering
trust-policy + .gbrain-source reads-only semantics.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan 2026-05-27 08:34:15 -07:00
parent 17293cfb6c
commit b6b3fbc5e3
No known key found for this signature in database
GPG Key ID: C1F69E85C74EFE1D
2 changed files with 271 additions and 40 deletions

View File

@ -0,0 +1,208 @@
# gbrain write surfaces — what lands where, and how to verify
This doc serves two audiences:
1. **Agents**: when a planning skill renders the compact `## Brain Context
Load` or `## Save Results to Brain` blocks, those blocks reference this
doc. Read §Context Load or §Save Template here on-demand when you're
actually using gbrain. Skip entirely if `gbrain` is not on PATH.
2. **Humans**: after running a planning skill against a real brain, use
the manual-probe sections to confirm the page actually landed.
## What lands where
| Host + detection state | What renders in the planning-skill SKILL.md |
|---|---|
| Any host + `gstack-config gbrain-refresh` reports `gbrain_local_status: "ok"` | Compressed brain-aware blocks render. Agent reads this doc on-demand when it actually saves. ~250 token overhead per planning skill. |
| Any host + gbrain not detected | Blocks suppressed at gen-time. Zero token overhead. Calibration takes still render (separate resolver, host-agnostic). |
| GBrain or Hermes host | Blocks always render regardless of detection — these hosts ship gbrain integration as a first-class concern. |
`.gbrain-source` pins **reads** only — writes go to the default engine
configured in `~/.gbrain/config.json`. Documented at
`bin/gstack-gbrain-sync.ts` for code-lookup resolvers; gstack treats the
same contract as load-bearing for artifact `put` semantics. If a user
reports writes landing in the wrong source, look here first.
Trust policy (`personal` vs `shared`, per endpoint hash) gates auto-push
and writeback. Set via `gstack-config set
brain_trust_policy@<endpoint-hash> personal`. Local PGLite installs
auto-default to `personal`; remote-MCP installs prompt during
`/setup-gbrain` step 9.5.
## §Context Load (agent reads this when running a planning skill)
Before starting, search the brain for relevant context:
1. **Extract 2-4 keywords** from the user's request. Pick nouns, error
names, file paths, technical terms — NOT verbs or adjectives.
Example: for "the login page is broken after deploy", search for
`login broken deploy`.
2. **Search**: `gbrain search "<keyword1 keyword2>"`. Returns lines like
`[slug] Title (score: 0.85) - first line of content...`.
3. **If few results** (under 3): broaden to the single most specific
keyword and search again. If still few, proceed without brain context.
4. **Read top 3 results**: `gbrain get_page "<slug>"` for each. Stop
after 3 — diminishing returns past that.
5. **Use the context** to inform your analysis. Cite specific slugs in
your output when a brain page changed your thinking.
If `gbrain search` returns any non-zero exit (gbrain not on PATH, network
flake, throttle), treat as transient: proceed without brain context. Do
not retry inline — the user can re-run the skill later.
## §Save Template (agent reads this when actually saving)
After completing the skill, save the output. The compact resolver block
already shows the slug prefix + title + tag for your specific skill (e.g.
`gbrain put "ceo-plans/<feature-slug>" ...`). The full template:
```bash
gbrain put "<slug-prefix>/<feature-slug>" --content "$(cat <<'EOF'
---
title: "<Title>: <feature name>"
tags: [<tag>, <feature-slug>]
---
<skill output in markdown the actual deliverable, not a summary>
EOF
)"
```
**Slug guidance**: `<feature-slug>` should be kebab-case, lowercase, and
unique within the prefix. Prefer concrete project/feature names over
abstract labels. Example: `auth-rate-limit` not `security-fix`.
**Title guidance**: the constant prefix (e.g. "CEO Plan", "Eng Review")
is fixed; the suffix is the human-readable name of the feature/topic.
**Tag guidance**: the first tag is the constant `<tag>` from the skill's
metadata (e.g. `ceo-plan`, `eng-review`). The second tag is the
`<feature-slug>` so cross-page traversal works. Add more tags if obvious
relationships exist (e.g. `[ceo-plan, auth-rate-limit, security]`).
### Entity-stub enrichment
After saving the main page, extract person and organization names
mentioned in the output. For each one:
```bash
# Check if a page exists first
gbrain search "<entity name>"
# If no match, create a stub
gbrain put "entities/<entity-slug>" --content "$(cat <<'EOF'
---
title: "<Person or Company Name>"
tags: [entity, person]
---
Stub page. Mentioned in <skill name> output. Replace with real bio when relevant.
EOF
)"
```
**Only extract real names** — actual person names (e.g. "Garry Tan") and
company/organization names (e.g. "Y Combinator"). Skip product names,
feature names, section headings, technical terms (CSS class names,
function names), and file paths. When in doubt, skip.
`tags: [entity, person]` for people, `tags: [entity, organization]` for
companies/teams.
### Error handling
- **Throttle**: exit code 1 with stderr containing `throttle`, `rate
limit`, `capacity`, or `busy`. Defer the save and move on — the brain
is busy; the content isn't lost, just not persisted this run.
- **Any other non-zero exit**: treat as transient failure. Do not retry
inline — the user can re-run the skill or run
`gstack-config gbrain-refresh` if they suspect gbrain itself is
misconfigured.
- **`gbrain: command not found`**: gbrain isn't on PATH. The compact
resolver block told you to skip — you shouldn't reach this code. If
you somehow did, silently skip and continue.
### Backlinks
If your save output mentions another brain page by name or topic, add a
backlink line at the bottom of the markdown body:
```
Related: [[other-page-slug]], [[another-slug]]
```
gbrain auto-resolves `[[slug]]` syntax into a clickable link in the
rendered page. Add backlinks only when the relationship is concrete
(e.g. "this CEO plan depends on the eng review at
`eng-reviews/auth-rate-limit`"). Don't fabricate connections.
### Completion summary
In your final skill output, note brain utilization in one line:
"Brain: read 3 pages, saved 1 page, enriched 2 entity stubs, 0 throttles."
This helps the user see brain coverage growing over time.
## Persistence verification (automated)
The matched-pair "is the data we hope to save actually being saved?"
question is covered by `test/skill-e2e-gbrain-roundtrip-local.test.ts`:
real `gbrain init --pglite` + `gbrain put` + `gbrain get` round-trip
against an isolated temp HOME. Periodic-tier. Skips when
`VOYAGE_API_KEY` is unset or gbrain CLI is missing from PATH.
Run it before opening a PR that touches the resolver:
```bash
EVALS=1 EVALS_TIER=periodic VOYAGE_API_KEY=$VOYAGE_API_KEY \
bun test test/skill-e2e-gbrain-roundtrip-local.test.ts
```
If you do want to spot-check by hand against your own brain after a
real planning-skill run (debugging a specific page that the agent
should have saved):
```bash
gbrain get "<prefix>/<slug>" # expect markdown + frontmatter
gbrain search "<slug fragment>" # expect slug in top results
gbrain sources list # confirm gstack-brain-<user> source
gbrain get "entities/<person>" # expect stub per named person
```
## Remote / Supabase / thin-client-MCP routing
The resolver emits a single CLI shape — `gbrain put "<slug>" --content
"..."` — that works against every engine gbrain supports. The CLI
internally routes to local PGLite, remote Supabase, or a remote MCP
endpoint depending on the user's `~/.gbrain/config.json`. **gstack
doesn't test that routing**: the storage layer is gbrain's contract to
honor, and the same CLI invocation we test against local PGLite is the
one that fires against any other engine.
If you're on Supabase or thin-client MCP and writes aren't landing:
1. `gbrain doctor --fast --json` — engine health check. If anything
reports `error`, fix that first.
2. `gstack-config get brain_trust_policy@<endpoint-hash>` must be
`personal` for auto-write. Run `gstack-config endpoint-hash` to get
the active hash. If `shared`, the agent prompts before writes — if
you declined, re-run the skill.
3. If trust policy is `personal` and `gbrain doctor` is clean but the
page still isn't there, file an issue against gbrain — gstack's
CLI call shape is the same as what T11 (`gbrain-roundtrip-local`)
exercises.
## What's NOT verified by automation
- **Calibration takes (`takes_add`)**: today these fall back to
fence-block writes inside a `gbrain put` because
`BRAIN_CALIBRATION_WRITEBACK` is FALSE pending gbrain v0.42+ shipping
the `takes_add` MCP op. When the flag flips, re-run the probe in this
doc against `/office-hours` and confirm `gbrain takes_list` surfaces a
`kind=bet` entry with the expected weight (0.9 for office-hours, per
`scripts/brain-cache-spec.ts:151-157`).
- **Per-skill E2E for the other 4 planning skills**: only `/office-hours`
has fake-CLI E2E coverage (`test/skill-e2e-office-hours-brain-writeback.test.ts`).
The resolver unit test (`test/resolvers-gbrain-save-results.test.ts`)
covers wiring for all 5. Per-skill E2E expansion is tracked in TODOS.md.
- **`.gbrain-source` write semantics**: gstack treats the documented
reads-only contract as load-bearing, but doesn't independently verify
that gbrain CLI never re-routes writes based on the pin. If you find a
case where it does, that's a gbrain bug to file upstream.

View File

@ -26,72 +26,95 @@ import {
getInvalidationTargets,
} from '../brain-cache-spec';
// Per-skill slug + title + tag metadata for SAVE_RESULTS. The full save
// template (heredoc body, entity-stub instructions, throttle handling,
// backlinks) lives in docs/gbrain-write-surfaces.md §Save Template and is
// read on-demand by the agent. Compressing the inline prose keeps the
// token footprint at ~150 tokens per skill (down from ~500), so users with
// gbrain installed pay a small overhead and users without it (whose hosts
// have GBRAIN_SAVE_RESULTS suppressed at gen-time) pay nothing.
interface SkillSaveMeta {
slugPrefix: string;
title: string;
tag: string;
}
const skillSaveMap: Record<string, SkillSaveMeta> = {
'office-hours': { slugPrefix: 'office-hours', title: 'Office Hours', tag: 'design-doc' },
'investigate': { slugPrefix: 'investigations', title: 'Investigation', tag: 'investigation' },
'plan-ceo-review': { slugPrefix: 'ceo-plans', title: 'CEO Plan', tag: 'ceo-plan' },
'plan-eng-review': { slugPrefix: 'eng-reviews', title: 'Eng Review', tag: 'eng-review' },
'plan-design-review': { slugPrefix: 'design-reviews', title: 'Design Review', tag: 'design-review' },
'plan-devex-review': { slugPrefix: 'devex-reviews', title: 'Devex Review', tag: 'devex-review' },
'retro': { slugPrefix: 'retros', title: 'Retro', tag: 'retro' },
'ship': { slugPrefix: 'releases', title: 'Release', tag: 'release' },
'cso': { slugPrefix: 'security-audits', title: 'Security Audit', tag: 'security-audit' },
'design-consultation': { slugPrefix: 'design-systems', title: 'Design System', tag: 'design-system' },
};
export function generateGBrainContextLoad(ctx: TemplateContext): string {
let base = `## Brain Context Load
Before starting this skill, search your brain for relevant context:
**Skip this entire section if \`gbrain\` is not on PATH.**
1. Extract 2-4 keywords from the user's request (nouns, error names, file paths, technical terms).
Search GBrain: \`gbrain search "keyword1 keyword2"\`
Example: for "the login page is broken after deploy", search \`gbrain search "login broken deploy"\`
Search returns lines like: \`[slug] Title (score: 0.85) - first line of content...\`
2. If few results, broaden to the single most specific keyword and search again.
3. For each result page, read it: \`gbrain get_page "<page_slug>"\`
Read the top 3 pages for context.
4. Use this brain context to inform your analysis.
Extract 2-4 keywords from the user's request. Search the brain:
\`gbrain search "<keywords>"\`. Read the top 3 results with
\`gbrain get_page "<slug>"\`. Use that context to inform your analysis.
If GBrain is not available or returns no results, proceed without brain context.
Any non-zero exit code from gbrain commands should be treated as a transient failure.`;
If \`gbrain search\` returns no results or any non-zero exit, proceed
without brain context. Full search/read protocol + examples:
see \`docs/gbrain-write-surfaces.md\` §Context Load.`;
if (ctx.skillName === 'investigate') {
base += `\n\nIf the user's request is about tracking, extracting, or researching structured data (e.g., "track this data", "extract from emails", "build a tracker"), route to GBrain's data-research skill instead: \`gbrain call data-research\`. This skill has a 7-phase pipeline optimized for structured data extraction.`;
base += `\n\nFor structured-data extraction requests ("track this", "extract from emails", "build a tracker"), route to GBrain's data-research skill instead: \`gbrain call data-research\`.`;
}
return base;
}
export function generateGBrainSaveResults(ctx: TemplateContext): string {
// gbrain v0.18+ renamed `put_page` → `put <slug>` and moved --title/--tags
// into YAML frontmatter inside --content. These templates render into
// SKILL.md files as user-facing instructions; using the old subcommand
// ships broken copy-paste to every gstack user.
const skillSaveMap: Record<string, string> = {
'office-hours': 'Save the design document as a brain page:\n```bash\ngbrain put "office-hours/<project-slug>" --content "$(cat <<\'EOF\'\n---\ntitle: "Office Hours: <project name>"\ntags: [design-doc, <project-slug>]\n---\n<design doc content in markdown>\nEOF\n)"\n```',
'investigate': 'Save the root cause analysis as a brain page:\n```bash\ngbrain put "investigations/<issue-slug>" --content "$(cat <<\'EOF\'\n---\ntitle: "Investigation: <issue summary>"\ntags: [investigation, <affected-files>]\n---\n<investigation findings in markdown>\nEOF\n)"\n```',
'plan-ceo-review': 'Save the CEO plan as a brain page:\n```bash\ngbrain put "ceo-plans/<feature-slug>" --content "$(cat <<\'EOF\'\n---\ntitle: "CEO Plan: <feature name>"\ntags: [ceo-plan, <feature-slug>]\n---\n<scope decisions and vision in markdown>\nEOF\n)"\n```',
'retro': 'Save the retrospective as a brain page:\n```bash\ngbrain put "retros/<date>" --content "$(cat <<\'EOF\'\n---\ntitle: "Retro: <date range>"\ntags: [retro, <date>]\n---\n<retro output in markdown>\nEOF\n)"\n```',
'plan-eng-review': 'Save the architecture decisions as a brain page:\n```bash\ngbrain put "eng-reviews/<feature-slug>" --content "$(cat <<\'EOF\'\n---\ntitle: "Eng Review: <feature name>"\ntags: [eng-review, <feature-slug>]\n---\n<review findings and decisions in markdown>\nEOF\n)"\n```',
'ship': 'Save the release notes as a brain page:\n```bash\ngbrain put "releases/<version>" --content "$(cat <<\'EOF\'\n---\ntitle: "Release: <version>"\ntags: [release, <version>]\n---\n<changelog entry and deploy details in markdown>\nEOF\n)"\n```',
'cso': 'Save the security audit as a brain page:\n```bash\ngbrain put "security-audits/<date>" --content "$(cat <<\'EOF\'\n---\ntitle: "Security Audit: <date>"\ntags: [security-audit, <date>]\n---\n<findings and remediation status in markdown>\nEOF\n)"\n```',
'design-consultation': 'Save the design system as a brain page:\n```bash\ngbrain put "design-systems/<project-slug>" --content "$(cat <<\'EOF\'\n---\ntitle: "Design System: <project name>"\ntags: [design-system, <project-slug>]\n---\n<design decisions in markdown>\nEOF\n)"\n```',
};
// gbrain v0.18+ uses `gbrain put <slug>` (NOT the deprecated `put_page`
// MCP op). Compressed in v1.50.0.0: the inline heredoc + entity-stub +
// throttle + backlink prose moved to docs/gbrain-write-surfaces.md
// §Save Template, which the agent reads on demand when it actually
// saves. The compact pointer keeps non-gbrain users' token overhead
// near zero when their host's static suppression is overridden by
// detection.
const meta = skillSaveMap[ctx.skillName];
const saveInstruction = skillSaveMap[ctx.skillName] || 'Save the skill output as a brain page if the results are worth preserving:\n```bash\ngbrain put "<slug>" --content "$(cat <<\'EOF\'\n---\ntitle: "<descriptive title>"\ntags: [<relevant>, <tags>]\n---\n<content in markdown>\nEOF\n)"\n```';
if (!meta) {
return `## Save Results to Brain
**Skip this entire section if \`gbrain\` is not on PATH.**
If the skill output is worth preserving, save it via
\`gbrain put "<slug>" --content "<frontmatter + markdown>"\`. Full template
(heredoc body, frontmatter shape, entity-stub instructions, throttle
handling): see \`docs/gbrain-write-surfaces.md\` §Save Template.`;
}
return `## Save Results to Brain
After completing this skill, persist the results to your brain for future reference:
**Skip this entire section if \`gbrain\` is not on PATH.**
${saveInstruction}
After completing this skill, save the output:
After saving the page, extract and enrich mentioned entities: for each actual person name or company/organization name found in the output, \`gbrain search "<entity name>"\` to check if a page exists. If not, create a stub page:
\`\`\`bash
gbrain put "entities/<entity-slug>" --content "$(cat <<'EOF'
gbrain put "${meta.slugPrefix}/<feature-slug>" --content "$(cat <<'EOF'
---
title: "<Person or Company Name>"
tags: [entity, person]
title: "${meta.title}: <feature name>"
tags: [${meta.tag}, <feature-slug>]
---
Stub page. Mentioned in <skill name> output.
<skill output in markdown>
EOF
)"
\`\`\`
Only extract actual person names and company/organization names. Skip product names, section headings, technical terms, and file paths.
Throttle errors appear as: exit code 1 with stderr containing "throttle", "rate limit", "capacity", or "busy". If GBrain returns a throttle or rate-limit error on any save operation, defer the save and move on. The brain is busy the content is not lost, just not persisted this run. Any other non-zero exit code should also be treated as a transient failure.
Add backlinks to related brain pages if they exist. If GBrain is not available, skip this step.
After brain operations complete, note in your completion output: how many pages were found in the initial search, how many entities were enriched, and whether any operations were throttled. This helps the user see brain utilization over time.`;
Then extract person/org entities and create stub pages for each one.
Throttle errors (exit 1 with "throttle"/"rate limit"/"busy") and any
other non-zero exit are transient don't retry inline. Full entity-stub
template, throttle handling, and backlink protocol:
see \`docs/gbrain-write-surfaces.md\` §Save Template.`;
}
// ────────────────────────────────────────────────────────────────────