Files
gstack/docs/gbrain-write-surfaces.md
T
f30b7b788a v1.91.13.0 fix: severe bug wave (autoplan guard, land-and-deploy CI gate, project identity, gbrain, review gates) (#3013)
* fix(land-and-deploy): never merge over red, pending or missing CI (#2995)

/land-and-deploy gated only on required checks, so a repo with none
(every GitHub Free private repo, any repo without branch protection)
skipped the CI wait and could merge over red CI. The verdict now comes
from bin/gstack-ci-gate, a tested helper bound to the head SHA: all
checks by default, cancel/unknown buckets fail, NO_CHECKS needs explicit
per-head approval, and both merge commands (including --auto) run only
after a PASS for the same SHA they pin with --match-head-commit.

Co-authored-by: harshitgavita-07 <harshit.gavita@gmail.com>

* fix(slug): give nested-group projects their own state bucket and verify checkpoint identity (#3003, #2901)

gstack-slug kept only the last two remote path segments, so
customer-a/product/repo and customer-b/product/repo shared one bucket
and /context-restore could present another project's checkpoint.

- One canonical-remote rule (bash + TS, golden vectors) used by all six
  resolvers: lowercased host, no userinfo/port/.git, Azure DevOps and
  Bitbucket Server normalized. 3+ segment remotes get
  <last-two>-<16 hex>; two-segment remotes (all of GitHub) are unchanged.
- Versioned sticky cache (v2:) keeps cache hits git-free.
- context-save stamps the credential-free remote and root;
  context-restore only treats this project's checkpoints as latest,
  reports foreign/unverified ones first, and treats a different root
  with the same remote (Conductor handoff) as information.
- gstack-slug --adopt-legacy copies only files the user confirms.
- question-preference-hook reads the same versioned cache, so never-ask
  preferences fire; unknown identity asks instead of auto-deciding.

* fix(gbrain): brain context loads, managed sync works, memory sync stops duplicating (#2883, #2985, #2922)

- brain-context-load called 'gbrain list_pages' (an MCP tool name), so
  every skill's brain context was 0 bytes. It now uses 'gbrain list'
  with gbrain's real filter flags, and prints one line when queries fail.
- The code-stage sync always passes --no-pull (managed gbrain >= 0.51
  refuses without it); a gbrain that rejects the flag fails with an
  upgrade message and is never retried without it. stderr is streamed
  with a bounded tail and quoted in failure summaries.
- /sync-gbrain gains --sources (and GSTACK_MEMORY_INGEST_SOURCES); by
  default it skips types already synced through a federated curated
  source, so curated pages stop being re-duplicated.

Co-authored-by: Vitor Cepeda Lopes <vitor@vitorcepedalopes.com>
Co-authored-by: harshitgavita-07 <harshit.gavita@gmail.com>

* fix(codex,cso): clean Codex reviews stop failing; semgrep and trivy SARIF results import (#2769, #3011)

- Codex review gate is PASS / FAIL / UNVERIFIED. Untagged output (what
  a clean 'codex review --base' prints) is UNVERIFIED, not FAIL, and
  never a false PASS; P2/P3-only output passes.
- import-sarif resolves semgrep's undeclared %SRCROOT% and trivy's
  ROOTPATH (including git-URL targets) through explicit, captured
  mappings; declared bases must sit inside the source root or the
  run's checkout, URIs are percent-decoded, and rejected results are
  counted with rule, base and path instead of silently dropped.

* fix: version strings are not IPs, failed update checks are not 'up to date', private security reporting (#2856, #2786, #2984)

- The pre-push redact hook exempts a root VERSION file that is only a
  version string and the version token in CHANGELOG release headings;
  the engine allowlist is untouched.
- gstack-update-check caches an unreadable remote as CHECK_FAILED with
  a short TTL instead of UP_TO_DATE; /gstack-upgrade never reports
  'latest' after a failed check.
- SECURITY.md points reporters at GitHub private vulnerability
  reporting.
- pr-title-sync (pull_request_target, write token) pins actions/checkout
  to a reviewed SHA.

* fix(autoplan): publication guard accepts real Claude Code journals (#3007, #3009, #2968, #2977, #2986, #3006)

The guard required a session journal to start with a user message, but
Claude Code starts it with SessionStart hook attachments (and a forked
compacted session starts with a compact_boundary), so every phase was
denied for anyone with a SessionStart hook. Windows path spellings
(C:/, /c/, drive case) were rejected too.

- Reader accepts the captured startup, compact, clear and fork shapes
  (claude 2.1.284 fixture), computes root uniqueness over every
  candidate, and returns typed reason codes instead of one string.
- Hard denials (competing root, foreign cwd, sidechain, agent, cycle,
  malformed, identity) say what happened and how to run the reviews by
  hand; unflushed journals still retry.
- A well-formed, stable journal whose root shape is unrecognized now
  warns ('phase publication was NOT verified') and continues, without
  overriding Claude Code's own permission check; no bypass switch.
- Windows paths fold before validation, so '..' is still rejected.
- Periodic drift canary runs the reader on fresh journals from the
  pinned claude.

Co-authored-by: Charles M Berg <77517285+CharlesBerg85@users.noreply.github.com>
Co-authored-by: laurenbdaniels-coder <264343335+laurenbdaniels-coder@users.noreply.github.com>
Co-authored-by: Jordan Mayer <176445995+maydaycyber@users.noreply.github.com>
Co-authored-by: elmesery-dev <elmesery.dev@gmail.com>

* v1.91.13.0: severe bug fix wave release notes, stale gbrain verbs in docs

* test: seed the versioned slug cache in the memory-injection deny case (#2901)

The preference hook now resolves the project bucket from gstack-slug's
v2 slug-cache entry instead of basename(cwd); this fixture still wrote
preferences under the basename bucket without the entry the skill
preamble always writes first.

* fix: full-suite follow-ups for the fix wave

- gstack-slug's --help heredoc is over 512B, so it gets the BASH_COMPAT=50
  pipe-deadlock guard like the other bins.
- Refresh the codex/factory ship goldens for the plan-gates slug change.
- The periodic lane gains the autoplan journal drift canary (107 paid
  files); raise the eval-slices cap to 25 so every slice still starts
  at once until its recorded duration lets the planner pack it.

* fix(plan-eng-review): clearer Step 0 sequencing, write routes and section outputs

The workflow judge scored plan-eng-review's instructions at
actionability 3.67 (bar 4) on text unchanged from main. Resolve the
ambiguities it named together, without changing any gate or output:
Step 0 names the Read's order and keeps one STOP; the pending-call,
read-only, forbidden-write and failed-save rules become one Write
routes block; header/label limits and grid checks are concrete;
Performance gets a checklist; each section has a stated output shape;
Lake Score is defined. Same total length (parity cap).

---------

Co-authored-by: harshitgavita-07 <harshit.gavita@gmail.com>
Co-authored-by: Vitor Cepeda Lopes <vitor@vitorcepedalopes.com>
Co-authored-by: Charles M Berg <77517285+CharlesBerg85@users.noreply.github.com>
Co-authored-by: laurenbdaniels-coder <264343335+laurenbdaniels-coder@users.noreply.github.com>
Co-authored-by: Jordan Mayer <176445995+maydaycyber@users.noreply.github.com>
Co-authored-by: elmesery-dev <elmesery.dev@gmail.com>
2026-10-02 11:11:00 -07:00

9.7 KiB

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 selects the source for reads and writes made from that directory, including gbrain put. It does not select a storage engine: the engine is configured separately in ~/.gbrain/config.json. GBrain resolves an explicit --source first, then GBRAIN_SOURCE, then the nearest trusted .gbrain-source, followed by registered path and default-source rules. If a page lands in an unexpected source, check the effective source selection before treating a successful put as proof it reached the intended corpus.

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 "<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:

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
)"

Read the page back from the same working directory and account before reporting it as saved:

gbrain get "<slug-prefix>/<feature-slug>"

Confirm that the returned page contains the intended title and substantive output. If the read fails or returns another page, report the save as unverified and retain the output for retry; do not claim a durable result. The same rule applies to entity stubs.

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:

# 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.

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 and read back 1 page, enriched 2 entity stubs, 0 throttles." Count a page as saved only after its readback succeeds. 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:

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):

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.