mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-29 19:01:39 +00:00
refactor(docs): relocate verbose release process to docs/RELEASING.md
The highest-/ship-risk commit (isolated so it can revert alone). Moves the verbose
release + contributor procedure out of CLAUDE.md, keeping every ship-critical IRON
RULE inline so /ship + /document-release (which read CLAUDE.md) cannot regress.
Moved to docs/RELEASING.md: pre-ship test requirements; the CHANGELOG-branch-scoped
+ CHANGELOG voice + release-summary template; the 'To take advantage of vX' block
spec; version migrations + migration-is-canonical; schema state tracking; GitHub
Actions SHA maintenance; PR-descriptions-cover-the-branch; community-PR-wave;
checking-out-PRs-from-garrytan-agents.
Kept INLINE in CLAUDE.md (ship-critical IRON RULES — do NOT move):
- the Version-locations table (5-file sync) + the 3-line consistency audit
- Conductor branch=workspace
- Post-ship /document-release (MANDATORY)
- Privacy + Responsible-disclosure rules (Privacy also anchors the check-privacy
allowlist — the only place allowed to name the fork)
- PR-title-version-first
- never-hand-roll-ship (Skill routing)
Plus a new ## Releasing pointer ('Before any ship, read docs/RELEASING.md in full')
and a resolver row.
CLAUDE.md 61KB -> 39KB (592KB -> 39KB overall, 93% cut; ~9k tokens auto-loaded vs
~147k). CLAUDE.md size-gate tightened 90KB -> 60KB. The content-contract tests pin
that the inline IRON RULES (MAJOR.MINOR.PATCH.MICRO, document-release, hand-roll
ship) did NOT move out. The moved ranges carry no banned fork name, so RELEASING.md
needs no privacy allowlist entry. verify 30/30; bundle 225KB -> 204KB.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
163f044e27
commit
fa2f9de21e
@@ -112,7 +112,9 @@ diff-aware subset during fast iteration on a focused branch. Requires Docker
|
||||
Manual path: `bun test` plus the E2E lifecycle described in `./CLAUDE.md` (spin
|
||||
up the test Postgres container, run `bun run test:e2e`, tear it down).
|
||||
|
||||
Ship via the `/ship` skill, not by hand.
|
||||
Ship via the `/ship` skill, not by hand. The full release + contributor process
|
||||
(CHANGELOG voice, version-locations sync, PR conventions, community-PR-wave) lives in
|
||||
[`./docs/RELEASING.md`](./docs/RELEASING.md); read it before shipping.
|
||||
|
||||
## Privacy
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ detail on demand.)
|
||||
| eval methodology / metrics | `docs/eval/` |
|
||||
| brains vs sources / topology | `docs/architecture/brains-and-sources.md`, `topologies.md` |
|
||||
| skill routing | `skills/RESOLVER.md` |
|
||||
| shipping a release / CHANGELOG / PR conventions | `docs/RELEASING.md` (ship IRON RULES stay inline below) |
|
||||
|
||||
The per-file index (`## Key files`), the thin-client routing seam, and the testing
|
||||
discipline used to live inline here. They moved to the docs above so this file
|
||||
@@ -535,46 +536,20 @@ The /ship workflow's Step 1 should be augmented to run the mismatch
|
||||
check; until that lands upstream, ALWAYS run the check above before
|
||||
`/ship` invokes its first push or PR-create step.
|
||||
|
||||
## Pre-ship requirements
|
||||
|
||||
Before shipping (/ship) or reviewing (/review), always run the full test suite.
|
||||
Two equivalent paths:
|
||||
## Releasing
|
||||
|
||||
**Path A — local CI gate (recommended, v0.23.1+):**
|
||||
- `bun run ci:local` runs the entire stack inside Docker: gitleaks (host), unit
|
||||
tests with `DATABASE_URL` unset, and all 29 E2E files sequentially against a
|
||||
fresh pgvector container. Stronger than PR CI's 2-file Tier 1 set; closer to
|
||||
what nightly Tier 1 catches. Spins up + tears down postgres automatically via
|
||||
`docker-compose.ci.yml`. Override the host port with
|
||||
`GBRAIN_CI_PG_PORT=5435 bun run ci:local` if 5434 collides.
|
||||
- `bun run ci:local:diff` runs only the E2E files matched by the diff selector
|
||||
(`scripts/select-e2e.ts`), falling back to all 29 on unmapped src/ paths or
|
||||
schema/skills/package.json changes. Fast iteration during a focused branch.
|
||||
Before any ship, read **[docs/RELEASING.md](docs/RELEASING.md)** in full. It carries the
|
||||
full release + contributor process: pre-ship test requirements (`bun run ci:local` / the
|
||||
E2E lifecycle), the CHANGELOG voice + release-summary template, the "To take advantage of
|
||||
vX" self-repair block, version migrations, the GitHub Actions SHA refresh, PR conventions,
|
||||
and the community-PR-wave process. **Use `/ship` — never hand-roll a release.**
|
||||
|
||||
**Path B — manual lifecycle (still supported):**
|
||||
- `bun test` — unit tests (no database required)
|
||||
- Follow the "E2E test DB lifecycle" steps above to spin up the test DB,
|
||||
run `bun run test:e2e`, then tear it down.
|
||||
|
||||
Both must pass. Do not ship with failing E2E tests. Do not skip E2E tests.
|
||||
|
||||
**Always run typecheck before pushing.** `bun test` (the bun runner)
|
||||
skips TypeScript type checking — it only enforces runtime behavior.
|
||||
Three ways to actually gate on types:
|
||||
|
||||
1. `bun run test` (npm script in `package.json`) — includes `bun run typecheck`
|
||||
plus the four shell pre-checks (`check-jsonb-pattern.sh`,
|
||||
`check-progress-to-stdout.sh`, `check-trailing-newline.sh`,
|
||||
`check-wasm-embedded.sh`) before the runner. Use this mid-branch.
|
||||
2. `bun run typecheck` — `tsc --noEmit` standalone. Fast (~5s on this repo).
|
||||
3. `bun run ci:local` — the full local CI gate from Path A.
|
||||
|
||||
The trap is: writing a new test, running `bun test test/foo.test.ts`,
|
||||
seeing it pass, pushing — and CI's separate typecheck stage rejects an
|
||||
invalid type literal that the runner accepted. Caught one of these
|
||||
shipping the v0.23.2 round-trip E2E (`type: 'reflection'` is not a
|
||||
member of `PageType`). Run `bun run typecheck` once before push, even
|
||||
when only test files changed.
|
||||
The ship-critical IRON RULES stay inline in this file (do NOT relocate them): the
|
||||
Version-locations table above (the 5-file sync + the 3-line VERSION/package.json/CHANGELOG
|
||||
audit), the Conductor branch=workspace rule (above), Post-ship `/document-release` (below),
|
||||
the Privacy + Responsible-disclosure rules (below), and the PR-title-version-first rule
|
||||
(below).
|
||||
|
||||
## Post-ship requirements (MANDATORY)
|
||||
|
||||
@@ -595,294 +570,6 @@ Files that MUST be checked on every ship:
|
||||
|
||||
A ship without updated docs is an incomplete ship. Period.
|
||||
|
||||
## CHANGELOG + VERSION are branch-scoped
|
||||
|
||||
**VERSION and CHANGELOG describe what THIS branch adds vs master, not how we got
|
||||
here.** Every feature branch that ships gets its own version bump and CHANGELOG
|
||||
entry. The entry is product release notes for users; it is not a log of internal
|
||||
decisions, review rounds, or codex findings.
|
||||
|
||||
**Write the CHANGELOG entry at /ship time, not during development.** Mid-branch
|
||||
iterations, review rounds (CEO/Eng/Codex/DX), and implementation detours belong
|
||||
in the plan file at `~/.claude/plans/`, not in the CHANGELOG. One unified entry
|
||||
per branch, covering what the branch added vs the base branch.
|
||||
|
||||
**Never edit a CHANGELOG entry that already landed on master.** If master has
|
||||
v0.18.2 and your branch adds features, bump to the next version (v0.19.0, not
|
||||
editing master's v0.18.2). When merging master into your branch, master may
|
||||
bring new CHANGELOG entries above yours — push your entry above master's
|
||||
latest and verify:
|
||||
|
||||
- Does CHANGELOG have your branch's own entry separate from master's entries?
|
||||
- Is VERSION higher than master's VERSION?
|
||||
- Is your entry the topmost `## [X.Y.Z]` entry?
|
||||
- `grep "^## \[" CHANGELOG.md` shows a contiguous version sequence?
|
||||
|
||||
If any answer is no, fix it before continuing.
|
||||
|
||||
**CHANGELOG is for users, not contributors.** Write like product release notes:
|
||||
|
||||
- Lead with what the user can now **do** that they couldn't before. Sell the capability.
|
||||
- Plain language, not implementation details. "You can now..." not "Refactored the..."
|
||||
- **Never mention internal artifacts**: plan file IDs, decision tags (D-CX-#, F-ENG-#),
|
||||
review rounds, codex findings, subcontractor credits. These are invisible to users.
|
||||
- Put contributor-facing changes in a separate `### For contributors` section at the bottom.
|
||||
- Every entry should make someone think "oh nice, I want to try that."
|
||||
|
||||
**What to omit:**
|
||||
- "Codex caught X that the CEO review missed" — private process detail.
|
||||
- "D-CX-3 split errors/warnings" — tag is meaningless to users; name the feature instead.
|
||||
- "Fix-wave PR #N supersedes #M" — supersede chains belong in PR bodies, not release notes.
|
||||
- "215 new cases, 3 decisions applied, 7 reviews cleared" — these are planning-mode metrics.
|
||||
|
||||
**What to keep:**
|
||||
- The user-facing change: what commands exist now, what flag was added, what behavior fixed.
|
||||
- Numbers that mean something to the user: TTHW, commands that timed out before, detection counts.
|
||||
- Upgrade instructions: `gbrain upgrade` + any manual step if needed.
|
||||
- Credit to external contributors when a community PR was incorporated.
|
||||
|
||||
## CHANGELOG voice + release-summary format
|
||||
|
||||
**IRON RULE: the CHANGELOG describes what the user gets, not how the work
|
||||
happened.** Nobody reading release notes cares that codex caught a bug, that
|
||||
the plan went through CEO + eng review, that the migration was originally
|
||||
numbered v68 and renumbered to v79 during master merge, or that two
|
||||
review rounds caught architectural mistakes. The reader cares what
|
||||
`gbrain brainstorm` does and how to use it. If a fact only exists because
|
||||
of the development process, it does NOT belong in the CHANGELOG.
|
||||
|
||||
**Specifically forbidden in CHANGELOG entries:**
|
||||
|
||||
- Any mention of review processes (CEO review, eng review, codex review,
|
||||
plan-eng-review, outside voice, adversarial review, autoplan, /review).
|
||||
- "What we caught and fixed before merging" sections. Bugs found pre-merge
|
||||
are not changes — they're things that didn't ship.
|
||||
- Plan file references, plan IDs, plan decision tags (D1, D14, D-CDX-3).
|
||||
- Migration version drama ("originally v68", "renumbered to v77", "claimed
|
||||
by parallel waves") — just say "Migration v79 adds X." If the user
|
||||
cares about migration ordering, they read the diff.
|
||||
- Round counts, finding counts, decision counts ("25 findings across 2
|
||||
rounds", "8 architectural decisions", "5/6 expansions accepted").
|
||||
- Names of internal collaborators ("codex caught", "the reviewer flagged",
|
||||
"Claude noticed").
|
||||
- "Plan + reviews" summary bullets. The plan lives in `~/.claude/plans/`;
|
||||
if a future reader wants the backstory they can grep there.
|
||||
- Any wording that frames a shipped feature as a *recovery* from a planning
|
||||
mistake ("the first plan was wrong", "we corrected the approach", "the
|
||||
shipped version supersedes the original design").
|
||||
|
||||
**Smell test:** read the entry as a stranger who has never touched gbrain.
|
||||
If any sentence makes them think "why are you telling me this?", cut it.
|
||||
Every sentence in the release-summary AND in the itemized changes must
|
||||
answer one of three questions: *What can I now do? How do I use it? What
|
||||
should I watch for after I upgrade?*
|
||||
|
||||
Every version entry in `CHANGELOG.md` MUST start with a release-summary section in
|
||||
the GStack/Garry voice — one viewport's worth of prose + tables that lands like a
|
||||
verdict, not marketing. The itemized changelog (subsections, bullets, files) goes
|
||||
BELOW that summary, separated by a `### Itemized changes` header.
|
||||
|
||||
The release-summary section gets read by humans, by the auto-update agent, and by
|
||||
anyone deciding whether to upgrade. The itemized list is for agents that need to
|
||||
know exactly what changed.
|
||||
|
||||
### Release-summary template
|
||||
|
||||
**Iron rule: lead ELI10, get precise after.** The first ~150 words of every entry
|
||||
must be readable by someone who does NOT know gbrain's internals. No file paths,
|
||||
no function names, no internal constants, no acronyms (no "RRF", no "knobsHash",
|
||||
no "MODE_BUNDLES", no "CDX-4"), no jargon that requires reading the codebase to
|
||||
parse. Lead with the user-visible behavior change, in everyday English, like
|
||||
you're explaining it to a smart engineer who has never opened the repo.
|
||||
|
||||
THEN, once the reader knows what shipped and why they'd care, drill into the
|
||||
precise details: real file paths, real function names, real config keys, real
|
||||
numbers. The precision part is required (the entry is also the technical record
|
||||
of what changed), but it lives AFTER the plain-English lead, never before it.
|
||||
|
||||
The shape:
|
||||
|
||||
1. **One-line bold headline.** What changed for the user, in human English. No
|
||||
jargon. No internal terms. Example good: "Your search stops boosting weak
|
||||
pages just because they have a lot of links pointing at them." Example bad:
|
||||
"PostFusionOpts gains floorRatio; KNOBS_HASH_VERSION bumped 2→3."
|
||||
2. **Plain-English opener** (~3-5 sentences). Describe the problem this fixes in
|
||||
everyday terms. Pretend the reader has a brain full of meeting notes and
|
||||
people pages and wants to know if this release helps them. Concrete example
|
||||
beats abstract description.
|
||||
3. **A "How to turn it on" or "How to use it" section** with paste-ready
|
||||
commands. Real flags, real config keys. This is where precision starts.
|
||||
4. **A "What you'd see in a concrete example" or "The X numbers that matter"
|
||||
section** with a table. Use everyday-language column headers ("Page",
|
||||
"Match quality", "Has many backlinks?") even when the underlying mechanism
|
||||
is technical. The table teaches what the feature does without requiring the
|
||||
reader to understand how.
|
||||
5. **A "What's safe to know about" or "Things to watch" section** for caveats,
|
||||
side effects, cache invalidation, mid-deploy notes. Still in plain language.
|
||||
6. **A "What we caught and fixed before merging" section** if the work went
|
||||
through review (CEO/eng/codex/outside-voice). Translate review findings into
|
||||
plain English. "We caught a stale-cache bug" beats "knobsHash() did not
|
||||
include floorRatio in the v=2 hash input."
|
||||
7. **`### Itemized changes`** (precision lives here). File paths, function
|
||||
names, types, constants, line numbers. This section is for engineers who
|
||||
need to know exactly what moved.
|
||||
|
||||
Voice rules (apply throughout):
|
||||
- No em dashes (use commas, periods, "...").
|
||||
- No AI vocabulary (delve, robust, comprehensive, nuanced, fundamental, etc.) or
|
||||
banned phrases ("here's the kicker", "the bottom line", etc.).
|
||||
- Real numbers, real file names, real commands AFTER the ELI10 lead. Not "fast"
|
||||
but "~30s on 30K pages." In the ELI10 lead, "fast enough that you won't
|
||||
notice" or "~30 seconds even on a big brain."
|
||||
- Short paragraphs, mix one-sentence punches with 2-3 sentence runs.
|
||||
- Connect to user outcomes: "the agent does ~3x less reading" beats "improved
|
||||
precision."
|
||||
- Be direct about quality. "Well-designed" or "this is a mess." No dancing.
|
||||
|
||||
**The smell test:** if someone who has never opened gbrain reads the first 150
|
||||
words and walks away knowing what shipped and whether they care, the entry
|
||||
passes. If they need to grep the codebase to follow along, rewrite the lead.
|
||||
|
||||
**Canonical examples in this CHANGELOG:** v0.35.6.0 (floor-ratio gate, written
|
||||
ELI10-lead-first), v0.34.4.0 (embed stale fix wave). Use those shapes when in
|
||||
doubt. Avoid the shape of entries that lead with internal constants or release
|
||||
mechanics; those exist in older history but should not be the model for new
|
||||
work.
|
||||
|
||||
Source material to pull from:
|
||||
- CHANGELOG.md previous entry for prior context
|
||||
- Latest `gbrain-evals/docs/benchmarks/[latest].md` for headline numbers (sibling repo)
|
||||
- Recent commits (`git log <prev-version>..HEAD --oneline`) for what shipped
|
||||
- Don't make up numbers. If a metric isn't in a benchmark or production data, don't
|
||||
include it. Say "no measurement yet" if asked.
|
||||
|
||||
Target length: ~250-350 words for the summary. Should render as one viewport.
|
||||
|
||||
### "To take advantage of v[version]" block (required, v0.13+)
|
||||
|
||||
After the release-summary and BEFORE `### Itemized changes`, every `## [X.Y.Z]`
|
||||
entry MUST include a human-readable self-repair block under the heading
|
||||
`## To take advantage of v[version]`.
|
||||
|
||||
Why: `gbrain upgrade` runs `gbrain post-upgrade` which runs `gbrain apply-migrations`.
|
||||
This chain has a known weak link — `upgrade.ts` catches post-upgrade failures as
|
||||
best-effort (so the binary still works). When that chain silently fails, users end
|
||||
up with half-upgraded brains. The self-repair block gives them a paste-ready
|
||||
recovery path; the v0.13+ `~/.gbrain/upgrade-errors.jsonl` trail + `gbrain doctor`
|
||||
integration close the loop.
|
||||
|
||||
Template (adapt the verify commands per release):
|
||||
|
||||
```markdown
|
||||
## To take advantage of v[version]
|
||||
|
||||
`gbrain upgrade` should do this automatically. If it didn't, or if `gbrain doctor`
|
||||
warns about a partial migration:
|
||||
|
||||
1. **Run the orchestrator manually:**
|
||||
```bash
|
||||
gbrain apply-migrations --yes
|
||||
```
|
||||
2. **Your agent reads `skills/migrations/v[version].md` the next time you interact with it.**
|
||||
[One sentence on whether headless agents need manual action, or whether the
|
||||
orchestrator already handled the mechanical side.]
|
||||
3. **Verify the outcome:**
|
||||
```bash
|
||||
[release-specific verify commands, e.g. `gbrain graph ... --depth 2`]
|
||||
gbrain stats
|
||||
```
|
||||
4. **If any step fails or the numbers look wrong,** please file an issue:
|
||||
https://github.com/garrytan/gbrain/issues with:
|
||||
- output of `gbrain doctor`
|
||||
- contents of `~/.gbrain/upgrade-errors.jsonl` if it exists
|
||||
- which step broke
|
||||
|
||||
This feedback loop is how the gbrain maintainers find fragile upgrade paths. Thank you.
|
||||
```
|
||||
|
||||
**Skip this block** for patches that are pure bug fixes with zero user-facing action
|
||||
(rare). If the release has a schema migration, data backfill, or new feature the
|
||||
user needs to verify, the block is required.
|
||||
|
||||
The v0.13.0 entry in CHANGELOG.md is the canonical example.
|
||||
|
||||
### Itemized changes (the existing rules)
|
||||
|
||||
Below the release summary, write `### Itemized changes` and continue with the
|
||||
detailed subsections (Knowledge Graph Layer, Schema migrations, Security hardening,
|
||||
Tests, etc.). Same rules as before:
|
||||
|
||||
- Lead with what the user can now DO that they couldn't before
|
||||
- Frame as benefits and capabilities, not files changed or code written
|
||||
- Make the user think "hell yeah, I want that"
|
||||
- Bad: "Added GBRAIN_VERIFY.md installation verification runbook"
|
||||
- Good: "Your agent now verifies the entire GBrain installation end-to-end, catching
|
||||
silent sync failures and stale embeddings before they bite you"
|
||||
- Bad: "Setup skill Phase H and Phase I added"
|
||||
- Good: "New installs automatically set up live sync so your brain never falls behind"
|
||||
- **Always credit community contributions.** When a CHANGELOG entry includes work from
|
||||
a community PR, name the contributor with `Contributed by @username`. Contributors
|
||||
did real work. Thank them publicly every time, no exceptions.
|
||||
|
||||
### Reference: v0.12.0 entry as canonical example
|
||||
|
||||
The v0.12.0 entry in CHANGELOG.md is the canonical example of the format. Match its
|
||||
structure for every future version: bold headline, lead paragraph, "numbers that
|
||||
matter" with BrainBench-style before/after table, "what this means" closer, then
|
||||
`### Itemized changes` with the detailed sections below.
|
||||
|
||||
## Version migrations
|
||||
|
||||
Create a migration file at `skills/migrations/v[version].md` when a release
|
||||
includes changes that existing users need to act on. The auto-update agent
|
||||
reads these files post-upgrade (Section 17, Step 4) and executes them.
|
||||
|
||||
**You need a migration file when:**
|
||||
- New setup step that existing installs don't have (e.g., v0.5.0 added live sync,
|
||||
existing users need to set it up, not just new installs)
|
||||
- New SKILLPACK section with a MUST ADD setup requirement
|
||||
- Schema changes that require `gbrain init` or manual SQL
|
||||
- Changed defaults that affect existing behavior
|
||||
- Deprecated commands or flags that need replacement
|
||||
- New verification steps that should run on existing installs
|
||||
- New cron jobs or background processes that should be registered
|
||||
|
||||
**You do NOT need a migration file when:**
|
||||
- Bug fixes with no behavior changes
|
||||
- Documentation-only improvements (the agent re-reads docs automatically)
|
||||
- New optional features that don't affect existing setups
|
||||
- Performance improvements that are transparent
|
||||
|
||||
**The key test:** if an existing user upgrades and does nothing else, will their
|
||||
brain work worse than before? If yes, migration file. If no, skip it.
|
||||
|
||||
Write migration files as agent instructions, not technical notes. Tell the agent
|
||||
what to do, step by step, with exact commands. See `skills/migrations/v0.5.0.md`
|
||||
for the pattern.
|
||||
|
||||
## Migration is canonical, not advisory
|
||||
|
||||
GBrain's job is to deliver a canonical, working setup to every user on upgrade.
|
||||
Anything that looks like a "host-repo change" — AGENTS.md, cron manifests,
|
||||
launchctl units, config files outside `~/.gbrain/` — is a GBrain migration
|
||||
step, not a nudge we leave for the host-repo maintainer. Migrations edit host
|
||||
files (with backups) to make the canonical setup real. Exceptions: changes
|
||||
that require human judgment (content edits, renames that break semantics,
|
||||
host-specific handler registration where shell-exec would be an RCE surface).
|
||||
Everything mechanical ships in the migration.
|
||||
|
||||
**Test:** if shipping a feature requires a sentence that starts with "in
|
||||
your AGENTS.md, add…" or "in your cron/jobs.json, rewrite…", the migration
|
||||
orchestrator should be doing that edit, not the user.
|
||||
|
||||
**The exception is host-specific code.** For custom Minion handlers
|
||||
(host-specific integrations like inbox sweeps or third-party API scanners), shipping them as a
|
||||
data file the worker would exec is an RCE surface. Those get registered in
|
||||
the host's own repo via the plugin contract (`docs/guides/plugin-handlers.md`);
|
||||
the migration orchestrator emits a structured TODO to
|
||||
`~/.gbrain/migrations/pending-host-work.jsonl` + the host agent walks the
|
||||
TODOs using `skills/migrations/v0.11.0.md` — stays host-agnostic, still
|
||||
canonical.
|
||||
|
||||
## Privacy rule: scrub real names from public docs
|
||||
|
||||
@@ -984,27 +671,6 @@ Applies retroactively: if you see a prior CHANGELOG entry naming attack-surface
|
||||
specifics, scrub it as a small cleanup commit, the same way a stale Wintermute
|
||||
reference gets swept.
|
||||
|
||||
## Schema state tracking
|
||||
|
||||
`~/.gbrain/update-state.json` tracks which recommended schema directories the user
|
||||
adopted, declined, or added custom. The auto-update agent (SKILLPACK Section 17)
|
||||
reads this during upgrades to suggest new schema additions without re-suggesting
|
||||
things the user already declined. The setup skill writes the initial state during
|
||||
Phase C/E. Never modify a user's custom directories or re-suggest declined ones.
|
||||
|
||||
## GitHub Actions SHA maintenance
|
||||
|
||||
All GitHub Actions in `.github/workflows/` are pinned to commit SHAs. Before shipping
|
||||
(`/ship`) or reviewing (`/review`), check for stale pins and update them:
|
||||
|
||||
```bash
|
||||
for action in actions/checkout oven-sh/setup-bun actions/upload-artifact actions/download-artifact softprops/action-gh-release gitleaks/gitleaks-action; do
|
||||
tag=$(grep -r "$action@" .github/workflows/ | head -1 | grep -o '#.*' | tr -d '# ')
|
||||
[ -n "$tag" ] && echo "$action@$tag: $(gh api repos/$action/git/ref/tags/$tag --jq .object.sha 2>/dev/null)"
|
||||
done
|
||||
```
|
||||
|
||||
If any SHA differs from what's in the workflow files, update the pin and version comment.
|
||||
|
||||
## PR title format — version FIRST (IRON RULE)
|
||||
|
||||
@@ -1027,75 +693,6 @@ This applies to `gh pr create` and every `gh pr edit --title`. When `/ship`
|
||||
(or any flow) sets a PR title, the version is the first token. Same rule for the
|
||||
final commit subject that carries the version bump.
|
||||
|
||||
## PR descriptions cover the whole branch
|
||||
|
||||
Pull request titles and bodies must describe **everything in the PR diff against the
|
||||
base branch**, not just the most recent commit you made. When you open or update a
|
||||
PR, walk the full commit range with `git log --oneline <base>..<head>` and write the
|
||||
body to cover all of it. Group by feature area (schema, code, tests, docs) — not
|
||||
chronologically by commit.
|
||||
|
||||
This matters because reviewers read the PR body to understand what's shipping. If
|
||||
the body only covers your last commit, they miss everything else and can't review
|
||||
properly. A 7-commit PR with a body that describes commit 7 is worse than no body
|
||||
at all — it actively misleads.
|
||||
|
||||
When in doubt, run `gh pr view <N> --json commits --jq '[.commits[].messageHeadline]'`
|
||||
to see what's actually in the PR before writing the body.
|
||||
|
||||
## Community PR wave process
|
||||
|
||||
Never merge external PRs directly into master. Instead, use the "fix wave" workflow:
|
||||
|
||||
1. **Categorize** — group PRs by theme (bug fixes, features, infra, docs)
|
||||
2. **Deduplicate** — if two PRs fix the same thing, pick the one that changes fewer
|
||||
lines. Close the other with a note pointing to the winner.
|
||||
3. **Collector branch** — create a feature branch (e.g. `garrytan/fix-wave-N`), cherry-pick
|
||||
or manually re-implement the best fixes from each PR. Do NOT merge PR branches directly —
|
||||
read the diff, understand the fix, and write it yourself if needed.
|
||||
4. **Test the wave** — verify with `bun test && bun run test:e2e` (full E2E lifecycle).
|
||||
Every fix in the wave must have test coverage.
|
||||
5. **Close with context** — every closed PR gets a comment explaining why and what (if
|
||||
anything) supersedes it. Contributors did real work; respect that with clear communication
|
||||
and thank them.
|
||||
6. **Ship as one PR** — single PR to master with all attributions preserved via
|
||||
`Co-Authored-By:` trailers. Include a summary of what merged and what closed.
|
||||
|
||||
**Community PR guardrails:**
|
||||
- Always AskUserQuestion before accepting commits that touch voice, tone, or
|
||||
promotional material (README intro, CHANGELOG voice, skill templates).
|
||||
- Never auto-merge PRs that remove YC references or "neutralize" the founder perspective.
|
||||
- Preserve contributor attribution in commit messages.
|
||||
|
||||
## Checking out PRs from garrytan-agents
|
||||
|
||||
`garrytan-agents` is the AI-authored PR account and is NOT a collaborator on
|
||||
this repo. Its PRs live in a fork, so GitHub Actions triggered by
|
||||
`pull_request` events on those PRs do not receive base-repo secrets. Any CI
|
||||
job that needs `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or similar will fail
|
||||
with empty-env auth errors, regardless of what's set on the base repo. This
|
||||
is a GitHub security default, not a config bug.
|
||||
|
||||
When the user says "check out <PR link>" and the PR is from `garrytan-agents`
|
||||
(or any other non-collaborator fork), move the branch into the base repo
|
||||
before running CI:
|
||||
|
||||
1. `gh pr checkout <N>` — pull down the fork's branch. Note the PR number and
|
||||
head branch name (`gh pr view <N> --json headRefName --jq .headRefName`).
|
||||
2. `git push origin HEAD:<branch-name>` — push the same branch to the base
|
||||
repo (origin points at `garrytan/gbrain`, not the fork). This is the move
|
||||
that gives CI access to secrets.
|
||||
3. `gh pr close <N> --comment "moving to base-repo branch for secret access"`
|
||||
— close the fork PR so the queue stays clean.
|
||||
4. `gh pr create --base master --head <branch-name>` — open the replacement
|
||||
PR from the base-repo branch. **Preserve the original PR's title and body
|
||||
verbatim** (`gh pr view <N> --json title,body`); contributor attribution
|
||||
moves to a `Co-Authored-By:` trailer if needed.
|
||||
|
||||
Why this over alternatives: adding `garrytan-agents` as a collaborator, or
|
||||
flipping the repo-wide "send secrets to fork PRs" toggle, both broaden
|
||||
secret distribution to every fork PR from that account or any fork. Moving
|
||||
the branch keeps secret scope tight to just the one PR being shipped.
|
||||
|
||||
## Skill routing
|
||||
|
||||
|
||||
@@ -0,0 +1,433 @@
|
||||
# Releasing & contributing (gbrain)
|
||||
|
||||
The full release + contributor process. CLAUDE.md keeps the ship-critical IRON RULES
|
||||
inline (the Version-locations table, branch=workspace, post-ship `/document-release`,
|
||||
the Privacy + Responsible-disclosure rules, PR-title-version-first, never-hand-roll-ship)
|
||||
and points here for everything else. **Before any ship, read this in full. Use `/ship` —
|
||||
never hand-roll a release.**
|
||||
|
||||
## Pre-ship requirements
|
||||
|
||||
Before shipping (/ship) or reviewing (/review), always run the full test suite.
|
||||
Two equivalent paths:
|
||||
|
||||
**Path A — local CI gate (recommended, v0.23.1+):**
|
||||
- `bun run ci:local` runs the entire stack inside Docker: gitleaks (host), unit
|
||||
tests with `DATABASE_URL` unset, and all 29 E2E files sequentially against a
|
||||
fresh pgvector container. Stronger than PR CI's 2-file Tier 1 set; closer to
|
||||
what nightly Tier 1 catches. Spins up + tears down postgres automatically via
|
||||
`docker-compose.ci.yml`. Override the host port with
|
||||
`GBRAIN_CI_PG_PORT=5435 bun run ci:local` if 5434 collides.
|
||||
- `bun run ci:local:diff` runs only the E2E files matched by the diff selector
|
||||
(`scripts/select-e2e.ts`), falling back to all 29 on unmapped src/ paths or
|
||||
schema/skills/package.json changes. Fast iteration during a focused branch.
|
||||
|
||||
**Path B — manual lifecycle (still supported):**
|
||||
- `bun test` — unit tests (no database required)
|
||||
- Follow the "E2E test DB lifecycle" steps above to spin up the test DB,
|
||||
run `bun run test:e2e`, then tear it down.
|
||||
|
||||
Both must pass. Do not ship with failing E2E tests. Do not skip E2E tests.
|
||||
|
||||
**Always run typecheck before pushing.** `bun test` (the bun runner)
|
||||
skips TypeScript type checking — it only enforces runtime behavior.
|
||||
Three ways to actually gate on types:
|
||||
|
||||
1. `bun run test` (npm script in `package.json`) — includes `bun run typecheck`
|
||||
plus the four shell pre-checks (`check-jsonb-pattern.sh`,
|
||||
`check-progress-to-stdout.sh`, `check-trailing-newline.sh`,
|
||||
`check-wasm-embedded.sh`) before the runner. Use this mid-branch.
|
||||
2. `bun run typecheck` — `tsc --noEmit` standalone. Fast (~5s on this repo).
|
||||
3. `bun run ci:local` — the full local CI gate from Path A.
|
||||
|
||||
The trap is: writing a new test, running `bun test test/foo.test.ts`,
|
||||
seeing it pass, pushing — and CI's separate typecheck stage rejects an
|
||||
invalid type literal that the runner accepted. Caught one of these
|
||||
shipping the v0.23.2 round-trip E2E (`type: 'reflection'` is not a
|
||||
member of `PageType`). Run `bun run typecheck` once before push, even
|
||||
when only test files changed.
|
||||
|
||||
|
||||
## CHANGELOG + VERSION are branch-scoped
|
||||
|
||||
**VERSION and CHANGELOG describe what THIS branch adds vs master, not how we got
|
||||
here.** Every feature branch that ships gets its own version bump and CHANGELOG
|
||||
entry. The entry is product release notes for users; it is not a log of internal
|
||||
decisions, review rounds, or codex findings.
|
||||
|
||||
**Write the CHANGELOG entry at /ship time, not during development.** Mid-branch
|
||||
iterations, review rounds (CEO/Eng/Codex/DX), and implementation detours belong
|
||||
in the plan file at `~/.claude/plans/`, not in the CHANGELOG. One unified entry
|
||||
per branch, covering what the branch added vs the base branch.
|
||||
|
||||
**Never edit a CHANGELOG entry that already landed on master.** If master has
|
||||
v0.18.2 and your branch adds features, bump to the next version (v0.19.0, not
|
||||
editing master's v0.18.2). When merging master into your branch, master may
|
||||
bring new CHANGELOG entries above yours — push your entry above master's
|
||||
latest and verify:
|
||||
|
||||
- Does CHANGELOG have your branch's own entry separate from master's entries?
|
||||
- Is VERSION higher than master's VERSION?
|
||||
- Is your entry the topmost `## [X.Y.Z]` entry?
|
||||
- `grep "^## \[" CHANGELOG.md` shows a contiguous version sequence?
|
||||
|
||||
If any answer is no, fix it before continuing.
|
||||
|
||||
**CHANGELOG is for users, not contributors.** Write like product release notes:
|
||||
|
||||
- Lead with what the user can now **do** that they couldn't before. Sell the capability.
|
||||
- Plain language, not implementation details. "You can now..." not "Refactored the..."
|
||||
- **Never mention internal artifacts**: plan file IDs, decision tags (D-CX-#, F-ENG-#),
|
||||
review rounds, codex findings, subcontractor credits. These are invisible to users.
|
||||
- Put contributor-facing changes in a separate `### For contributors` section at the bottom.
|
||||
- Every entry should make someone think "oh nice, I want to try that."
|
||||
|
||||
**What to omit:**
|
||||
- "Codex caught X that the CEO review missed" — private process detail.
|
||||
- "D-CX-3 split errors/warnings" — tag is meaningless to users; name the feature instead.
|
||||
- "Fix-wave PR #N supersedes #M" — supersede chains belong in PR bodies, not release notes.
|
||||
- "215 new cases, 3 decisions applied, 7 reviews cleared" — these are planning-mode metrics.
|
||||
|
||||
**What to keep:**
|
||||
- The user-facing change: what commands exist now, what flag was added, what behavior fixed.
|
||||
- Numbers that mean something to the user: TTHW, commands that timed out before, detection counts.
|
||||
- Upgrade instructions: `gbrain upgrade` + any manual step if needed.
|
||||
- Credit to external contributors when a community PR was incorporated.
|
||||
|
||||
## CHANGELOG voice + release-summary format
|
||||
|
||||
**IRON RULE: the CHANGELOG describes what the user gets, not how the work
|
||||
happened.** Nobody reading release notes cares that codex caught a bug, that
|
||||
the plan went through CEO + eng review, that the migration was originally
|
||||
numbered v68 and renumbered to v79 during master merge, or that two
|
||||
review rounds caught architectural mistakes. The reader cares what
|
||||
`gbrain brainstorm` does and how to use it. If a fact only exists because
|
||||
of the development process, it does NOT belong in the CHANGELOG.
|
||||
|
||||
**Specifically forbidden in CHANGELOG entries:**
|
||||
|
||||
- Any mention of review processes (CEO review, eng review, codex review,
|
||||
plan-eng-review, outside voice, adversarial review, autoplan, /review).
|
||||
- "What we caught and fixed before merging" sections. Bugs found pre-merge
|
||||
are not changes — they're things that didn't ship.
|
||||
- Plan file references, plan IDs, plan decision tags (D1, D14, D-CDX-3).
|
||||
- Migration version drama ("originally v68", "renumbered to v77", "claimed
|
||||
by parallel waves") — just say "Migration v79 adds X." If the user
|
||||
cares about migration ordering, they read the diff.
|
||||
- Round counts, finding counts, decision counts ("25 findings across 2
|
||||
rounds", "8 architectural decisions", "5/6 expansions accepted").
|
||||
- Names of internal collaborators ("codex caught", "the reviewer flagged",
|
||||
"Claude noticed").
|
||||
- "Plan + reviews" summary bullets. The plan lives in `~/.claude/plans/`;
|
||||
if a future reader wants the backstory they can grep there.
|
||||
- Any wording that frames a shipped feature as a *recovery* from a planning
|
||||
mistake ("the first plan was wrong", "we corrected the approach", "the
|
||||
shipped version supersedes the original design").
|
||||
|
||||
**Smell test:** read the entry as a stranger who has never touched gbrain.
|
||||
If any sentence makes them think "why are you telling me this?", cut it.
|
||||
Every sentence in the release-summary AND in the itemized changes must
|
||||
answer one of three questions: *What can I now do? How do I use it? What
|
||||
should I watch for after I upgrade?*
|
||||
|
||||
Every version entry in `CHANGELOG.md` MUST start with a release-summary section in
|
||||
the GStack/Garry voice — one viewport's worth of prose + tables that lands like a
|
||||
verdict, not marketing. The itemized changelog (subsections, bullets, files) goes
|
||||
BELOW that summary, separated by a `### Itemized changes` header.
|
||||
|
||||
The release-summary section gets read by humans, by the auto-update agent, and by
|
||||
anyone deciding whether to upgrade. The itemized list is for agents that need to
|
||||
know exactly what changed.
|
||||
|
||||
### Release-summary template
|
||||
|
||||
**Iron rule: lead ELI10, get precise after.** The first ~150 words of every entry
|
||||
must be readable by someone who does NOT know gbrain's internals. No file paths,
|
||||
no function names, no internal constants, no acronyms (no "RRF", no "knobsHash",
|
||||
no "MODE_BUNDLES", no "CDX-4"), no jargon that requires reading the codebase to
|
||||
parse. Lead with the user-visible behavior change, in everyday English, like
|
||||
you're explaining it to a smart engineer who has never opened the repo.
|
||||
|
||||
THEN, once the reader knows what shipped and why they'd care, drill into the
|
||||
precise details: real file paths, real function names, real config keys, real
|
||||
numbers. The precision part is required (the entry is also the technical record
|
||||
of what changed), but it lives AFTER the plain-English lead, never before it.
|
||||
|
||||
The shape:
|
||||
|
||||
1. **One-line bold headline.** What changed for the user, in human English. No
|
||||
jargon. No internal terms. Example good: "Your search stops boosting weak
|
||||
pages just because they have a lot of links pointing at them." Example bad:
|
||||
"PostFusionOpts gains floorRatio; KNOBS_HASH_VERSION bumped 2→3."
|
||||
2. **Plain-English opener** (~3-5 sentences). Describe the problem this fixes in
|
||||
everyday terms. Pretend the reader has a brain full of meeting notes and
|
||||
people pages and wants to know if this release helps them. Concrete example
|
||||
beats abstract description.
|
||||
3. **A "How to turn it on" or "How to use it" section** with paste-ready
|
||||
commands. Real flags, real config keys. This is where precision starts.
|
||||
4. **A "What you'd see in a concrete example" or "The X numbers that matter"
|
||||
section** with a table. Use everyday-language column headers ("Page",
|
||||
"Match quality", "Has many backlinks?") even when the underlying mechanism
|
||||
is technical. The table teaches what the feature does without requiring the
|
||||
reader to understand how.
|
||||
5. **A "What's safe to know about" or "Things to watch" section** for caveats,
|
||||
side effects, cache invalidation, mid-deploy notes. Still in plain language.
|
||||
6. **A "What we caught and fixed before merging" section** if the work went
|
||||
through review (CEO/eng/codex/outside-voice). Translate review findings into
|
||||
plain English. "We caught a stale-cache bug" beats "knobsHash() did not
|
||||
include floorRatio in the v=2 hash input."
|
||||
7. **`### Itemized changes`** (precision lives here). File paths, function
|
||||
names, types, constants, line numbers. This section is for engineers who
|
||||
need to know exactly what moved.
|
||||
|
||||
Voice rules (apply throughout):
|
||||
- No em dashes (use commas, periods, "...").
|
||||
- No AI vocabulary (delve, robust, comprehensive, nuanced, fundamental, etc.) or
|
||||
banned phrases ("here's the kicker", "the bottom line", etc.).
|
||||
- Real numbers, real file names, real commands AFTER the ELI10 lead. Not "fast"
|
||||
but "~30s on 30K pages." In the ELI10 lead, "fast enough that you won't
|
||||
notice" or "~30 seconds even on a big brain."
|
||||
- Short paragraphs, mix one-sentence punches with 2-3 sentence runs.
|
||||
- Connect to user outcomes: "the agent does ~3x less reading" beats "improved
|
||||
precision."
|
||||
- Be direct about quality. "Well-designed" or "this is a mess." No dancing.
|
||||
|
||||
**The smell test:** if someone who has never opened gbrain reads the first 150
|
||||
words and walks away knowing what shipped and whether they care, the entry
|
||||
passes. If they need to grep the codebase to follow along, rewrite the lead.
|
||||
|
||||
**Canonical examples in this CHANGELOG:** v0.35.6.0 (floor-ratio gate, written
|
||||
ELI10-lead-first), v0.34.4.0 (embed stale fix wave). Use those shapes when in
|
||||
doubt. Avoid the shape of entries that lead with internal constants or release
|
||||
mechanics; those exist in older history but should not be the model for new
|
||||
work.
|
||||
|
||||
Source material to pull from:
|
||||
- CHANGELOG.md previous entry for prior context
|
||||
- Latest `gbrain-evals/docs/benchmarks/[latest].md` for headline numbers (sibling repo)
|
||||
- Recent commits (`git log <prev-version>..HEAD --oneline`) for what shipped
|
||||
- Don't make up numbers. If a metric isn't in a benchmark or production data, don't
|
||||
include it. Say "no measurement yet" if asked.
|
||||
|
||||
Target length: ~250-350 words for the summary. Should render as one viewport.
|
||||
|
||||
### "To take advantage of v[version]" block (required, v0.13+)
|
||||
|
||||
After the release-summary and BEFORE `### Itemized changes`, every `## [X.Y.Z]`
|
||||
entry MUST include a human-readable self-repair block under the heading
|
||||
`## To take advantage of v[version]`.
|
||||
|
||||
Why: `gbrain upgrade` runs `gbrain post-upgrade` which runs `gbrain apply-migrations`.
|
||||
This chain has a known weak link — `upgrade.ts` catches post-upgrade failures as
|
||||
best-effort (so the binary still works). When that chain silently fails, users end
|
||||
up with half-upgraded brains. The self-repair block gives them a paste-ready
|
||||
recovery path; the v0.13+ `~/.gbrain/upgrade-errors.jsonl` trail + `gbrain doctor`
|
||||
integration close the loop.
|
||||
|
||||
Template (adapt the verify commands per release):
|
||||
|
||||
```markdown
|
||||
## To take advantage of v[version]
|
||||
|
||||
`gbrain upgrade` should do this automatically. If it didn't, or if `gbrain doctor`
|
||||
warns about a partial migration:
|
||||
|
||||
1. **Run the orchestrator manually:**
|
||||
```bash
|
||||
gbrain apply-migrations --yes
|
||||
```
|
||||
2. **Your agent reads `skills/migrations/v[version].md` the next time you interact with it.**
|
||||
[One sentence on whether headless agents need manual action, or whether the
|
||||
orchestrator already handled the mechanical side.]
|
||||
3. **Verify the outcome:**
|
||||
```bash
|
||||
[release-specific verify commands, e.g. `gbrain graph ... --depth 2`]
|
||||
gbrain stats
|
||||
```
|
||||
4. **If any step fails or the numbers look wrong,** please file an issue:
|
||||
https://github.com/garrytan/gbrain/issues with:
|
||||
- output of `gbrain doctor`
|
||||
- contents of `~/.gbrain/upgrade-errors.jsonl` if it exists
|
||||
- which step broke
|
||||
|
||||
This feedback loop is how the gbrain maintainers find fragile upgrade paths. Thank you.
|
||||
```
|
||||
|
||||
**Skip this block** for patches that are pure bug fixes with zero user-facing action
|
||||
(rare). If the release has a schema migration, data backfill, or new feature the
|
||||
user needs to verify, the block is required.
|
||||
|
||||
The v0.13.0 entry in CHANGELOG.md is the canonical example.
|
||||
|
||||
### Itemized changes (the existing rules)
|
||||
|
||||
Below the release summary, write `### Itemized changes` and continue with the
|
||||
detailed subsections (Knowledge Graph Layer, Schema migrations, Security hardening,
|
||||
Tests, etc.). Same rules as before:
|
||||
|
||||
- Lead with what the user can now DO that they couldn't before
|
||||
- Frame as benefits and capabilities, not files changed or code written
|
||||
- Make the user think "hell yeah, I want that"
|
||||
- Bad: "Added GBRAIN_VERIFY.md installation verification runbook"
|
||||
- Good: "Your agent now verifies the entire GBrain installation end-to-end, catching
|
||||
silent sync failures and stale embeddings before they bite you"
|
||||
- Bad: "Setup skill Phase H and Phase I added"
|
||||
- Good: "New installs automatically set up live sync so your brain never falls behind"
|
||||
- **Always credit community contributions.** When a CHANGELOG entry includes work from
|
||||
a community PR, name the contributor with `Contributed by @username`. Contributors
|
||||
did real work. Thank them publicly every time, no exceptions.
|
||||
|
||||
### Reference: v0.12.0 entry as canonical example
|
||||
|
||||
The v0.12.0 entry in CHANGELOG.md is the canonical example of the format. Match its
|
||||
structure for every future version: bold headline, lead paragraph, "numbers that
|
||||
matter" with BrainBench-style before/after table, "what this means" closer, then
|
||||
`### Itemized changes` with the detailed sections below.
|
||||
|
||||
## Version migrations
|
||||
|
||||
Create a migration file at `skills/migrations/v[version].md` when a release
|
||||
includes changes that existing users need to act on. The auto-update agent
|
||||
reads these files post-upgrade (Section 17, Step 4) and executes them.
|
||||
|
||||
**You need a migration file when:**
|
||||
- New setup step that existing installs don't have (e.g., v0.5.0 added live sync,
|
||||
existing users need to set it up, not just new installs)
|
||||
- New SKILLPACK section with a MUST ADD setup requirement
|
||||
- Schema changes that require `gbrain init` or manual SQL
|
||||
- Changed defaults that affect existing behavior
|
||||
- Deprecated commands or flags that need replacement
|
||||
- New verification steps that should run on existing installs
|
||||
- New cron jobs or background processes that should be registered
|
||||
|
||||
**You do NOT need a migration file when:**
|
||||
- Bug fixes with no behavior changes
|
||||
- Documentation-only improvements (the agent re-reads docs automatically)
|
||||
- New optional features that don't affect existing setups
|
||||
- Performance improvements that are transparent
|
||||
|
||||
**The key test:** if an existing user upgrades and does nothing else, will their
|
||||
brain work worse than before? If yes, migration file. If no, skip it.
|
||||
|
||||
Write migration files as agent instructions, not technical notes. Tell the agent
|
||||
what to do, step by step, with exact commands. See `skills/migrations/v0.5.0.md`
|
||||
for the pattern.
|
||||
|
||||
## Migration is canonical, not advisory
|
||||
|
||||
GBrain's job is to deliver a canonical, working setup to every user on upgrade.
|
||||
Anything that looks like a "host-repo change" — AGENTS.md, cron manifests,
|
||||
launchctl units, config files outside `~/.gbrain/` — is a GBrain migration
|
||||
step, not a nudge we leave for the host-repo maintainer. Migrations edit host
|
||||
files (with backups) to make the canonical setup real. Exceptions: changes
|
||||
that require human judgment (content edits, renames that break semantics,
|
||||
host-specific handler registration where shell-exec would be an RCE surface).
|
||||
Everything mechanical ships in the migration.
|
||||
|
||||
**Test:** if shipping a feature requires a sentence that starts with "in
|
||||
your AGENTS.md, add…" or "in your cron/jobs.json, rewrite…", the migration
|
||||
orchestrator should be doing that edit, not the user.
|
||||
|
||||
**The exception is host-specific code.** For custom Minion handlers
|
||||
(host-specific integrations like inbox sweeps or third-party API scanners), shipping them as a
|
||||
data file the worker would exec is an RCE surface. Those get registered in
|
||||
the host's own repo via the plugin contract (`docs/guides/plugin-handlers.md`);
|
||||
the migration orchestrator emits a structured TODO to
|
||||
`~/.gbrain/migrations/pending-host-work.jsonl` + the host agent walks the
|
||||
TODOs using `skills/migrations/v0.11.0.md` — stays host-agnostic, still
|
||||
canonical.
|
||||
|
||||
|
||||
## Schema state tracking
|
||||
|
||||
`~/.gbrain/update-state.json` tracks which recommended schema directories the user
|
||||
adopted, declined, or added custom. The auto-update agent (SKILLPACK Section 17)
|
||||
reads this during upgrades to suggest new schema additions without re-suggesting
|
||||
things the user already declined. The setup skill writes the initial state during
|
||||
Phase C/E. Never modify a user's custom directories or re-suggest declined ones.
|
||||
|
||||
## GitHub Actions SHA maintenance
|
||||
|
||||
All GitHub Actions in `.github/workflows/` are pinned to commit SHAs. Before shipping
|
||||
(`/ship`) or reviewing (`/review`), check for stale pins and update them:
|
||||
|
||||
```bash
|
||||
for action in actions/checkout oven-sh/setup-bun actions/upload-artifact actions/download-artifact softprops/action-gh-release gitleaks/gitleaks-action; do
|
||||
tag=$(grep -r "$action@" .github/workflows/ | head -1 | grep -o '#.*' | tr -d '# ')
|
||||
[ -n "$tag" ] && echo "$action@$tag: $(gh api repos/$action/git/ref/tags/$tag --jq .object.sha 2>/dev/null)"
|
||||
done
|
||||
```
|
||||
|
||||
If any SHA differs from what's in the workflow files, update the pin and version comment.
|
||||
|
||||
|
||||
## PR descriptions cover the whole branch
|
||||
|
||||
Pull request titles and bodies must describe **everything in the PR diff against the
|
||||
base branch**, not just the most recent commit you made. When you open or update a
|
||||
PR, walk the full commit range with `git log --oneline <base>..<head>` and write the
|
||||
body to cover all of it. Group by feature area (schema, code, tests, docs) — not
|
||||
chronologically by commit.
|
||||
|
||||
This matters because reviewers read the PR body to understand what's shipping. If
|
||||
the body only covers your last commit, they miss everything else and can't review
|
||||
properly. A 7-commit PR with a body that describes commit 7 is worse than no body
|
||||
at all — it actively misleads.
|
||||
|
||||
When in doubt, run `gh pr view <N> --json commits --jq '[.commits[].messageHeadline]'`
|
||||
to see what's actually in the PR before writing the body.
|
||||
|
||||
## Community PR wave process
|
||||
|
||||
Never merge external PRs directly into master. Instead, use the "fix wave" workflow:
|
||||
|
||||
1. **Categorize** — group PRs by theme (bug fixes, features, infra, docs)
|
||||
2. **Deduplicate** — if two PRs fix the same thing, pick the one that changes fewer
|
||||
lines. Close the other with a note pointing to the winner.
|
||||
3. **Collector branch** — create a feature branch (e.g. `garrytan/fix-wave-N`), cherry-pick
|
||||
or manually re-implement the best fixes from each PR. Do NOT merge PR branches directly —
|
||||
read the diff, understand the fix, and write it yourself if needed.
|
||||
4. **Test the wave** — verify with `bun test && bun run test:e2e` (full E2E lifecycle).
|
||||
Every fix in the wave must have test coverage.
|
||||
5. **Close with context** — every closed PR gets a comment explaining why and what (if
|
||||
anything) supersedes it. Contributors did real work; respect that with clear communication
|
||||
and thank them.
|
||||
6. **Ship as one PR** — single PR to master with all attributions preserved via
|
||||
`Co-Authored-By:` trailers. Include a summary of what merged and what closed.
|
||||
|
||||
**Community PR guardrails:**
|
||||
- Always AskUserQuestion before accepting commits that touch voice, tone, or
|
||||
promotional material (README intro, CHANGELOG voice, skill templates).
|
||||
- Never auto-merge PRs that remove YC references or "neutralize" the founder perspective.
|
||||
- Preserve contributor attribution in commit messages.
|
||||
|
||||
## Checking out PRs from garrytan-agents
|
||||
|
||||
`garrytan-agents` is the AI-authored PR account and is NOT a collaborator on
|
||||
this repo. Its PRs live in a fork, so GitHub Actions triggered by
|
||||
`pull_request` events on those PRs do not receive base-repo secrets. Any CI
|
||||
job that needs `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or similar will fail
|
||||
with empty-env auth errors, regardless of what's set on the base repo. This
|
||||
is a GitHub security default, not a config bug.
|
||||
|
||||
When the user says "check out <PR link>" and the PR is from `garrytan-agents`
|
||||
(or any other non-collaborator fork), move the branch into the base repo
|
||||
before running CI:
|
||||
|
||||
1. `gh pr checkout <N>` — pull down the fork's branch. Note the PR number and
|
||||
head branch name (`gh pr view <N> --json headRefName --jq .headRefName`).
|
||||
2. `git push origin HEAD:<branch-name>` — push the same branch to the base
|
||||
repo (origin points at `garrytan/gbrain`, not the fork). This is the move
|
||||
that gives CI access to secrets.
|
||||
3. `gh pr close <N> --comment "moving to base-repo branch for secret access"`
|
||||
— close the fork PR so the queue stays clean.
|
||||
4. `gh pr create --base master --head <branch-name>` — open the replacement
|
||||
PR from the base-repo branch. **Preserve the original PR's title and body
|
||||
verbatim** (`gh pr view <N> --json title,body`); contributor attribution
|
||||
moves to a `Co-Authored-By:` trailer if needed.
|
||||
|
||||
Why this over alternatives: adding `garrytan-agents` as a collaborator, or
|
||||
flipping the repo-wide "send secrets to fork PRs" toggle, both broaden
|
||||
secret distribution to every fork PR from that account or any fork. Moving
|
||||
the branch keeps secret scope tight to just the one PR being shipped.
|
||||
|
||||
+15
-416
@@ -125,7 +125,9 @@ diff-aware subset during fast iteration on a focused branch. Requires Docker
|
||||
Manual path: `bun test` plus the E2E lifecycle described in `./CLAUDE.md` (spin
|
||||
up the test Postgres container, run `bun run test:e2e`, tear it down).
|
||||
|
||||
Ship via the `/ship` skill, not by hand.
|
||||
Ship via the `/ship` skill, not by hand. The full release + contributor process
|
||||
(CHANGELOG voice, version-locations sync, PR conventions, community-PR-wave) lives in
|
||||
[`./docs/RELEASING.md`](./docs/RELEASING.md); read it before shipping.
|
||||
|
||||
## Privacy
|
||||
|
||||
@@ -242,6 +244,7 @@ detail on demand.)
|
||||
| eval methodology / metrics | `docs/eval/` |
|
||||
| brains vs sources / topology | `docs/architecture/brains-and-sources.md`, `topologies.md` |
|
||||
| skill routing | `skills/RESOLVER.md` |
|
||||
| shipping a release / CHANGELOG / PR conventions | `docs/RELEASING.md` (ship IRON RULES stay inline below) |
|
||||
|
||||
The per-file index (`## Key files`), the thin-client routing seam, and the testing
|
||||
discipline used to live inline here. They moved to the docs above so this file
|
||||
@@ -681,46 +684,20 @@ The /ship workflow's Step 1 should be augmented to run the mismatch
|
||||
check; until that lands upstream, ALWAYS run the check above before
|
||||
`/ship` invokes its first push or PR-create step.
|
||||
|
||||
## Pre-ship requirements
|
||||
|
||||
Before shipping (/ship) or reviewing (/review), always run the full test suite.
|
||||
Two equivalent paths:
|
||||
## Releasing
|
||||
|
||||
**Path A — local CI gate (recommended, v0.23.1+):**
|
||||
- `bun run ci:local` runs the entire stack inside Docker: gitleaks (host), unit
|
||||
tests with `DATABASE_URL` unset, and all 29 E2E files sequentially against a
|
||||
fresh pgvector container. Stronger than PR CI's 2-file Tier 1 set; closer to
|
||||
what nightly Tier 1 catches. Spins up + tears down postgres automatically via
|
||||
`docker-compose.ci.yml`. Override the host port with
|
||||
`GBRAIN_CI_PG_PORT=5435 bun run ci:local` if 5434 collides.
|
||||
- `bun run ci:local:diff` runs only the E2E files matched by the diff selector
|
||||
(`scripts/select-e2e.ts`), falling back to all 29 on unmapped src/ paths or
|
||||
schema/skills/package.json changes. Fast iteration during a focused branch.
|
||||
Before any ship, read **[docs/RELEASING.md](docs/RELEASING.md)** in full. It carries the
|
||||
full release + contributor process: pre-ship test requirements (`bun run ci:local` / the
|
||||
E2E lifecycle), the CHANGELOG voice + release-summary template, the "To take advantage of
|
||||
vX" self-repair block, version migrations, the GitHub Actions SHA refresh, PR conventions,
|
||||
and the community-PR-wave process. **Use `/ship` — never hand-roll a release.**
|
||||
|
||||
**Path B — manual lifecycle (still supported):**
|
||||
- `bun test` — unit tests (no database required)
|
||||
- Follow the "E2E test DB lifecycle" steps above to spin up the test DB,
|
||||
run `bun run test:e2e`, then tear it down.
|
||||
|
||||
Both must pass. Do not ship with failing E2E tests. Do not skip E2E tests.
|
||||
|
||||
**Always run typecheck before pushing.** `bun test` (the bun runner)
|
||||
skips TypeScript type checking — it only enforces runtime behavior.
|
||||
Three ways to actually gate on types:
|
||||
|
||||
1. `bun run test` (npm script in `package.json`) — includes `bun run typecheck`
|
||||
plus the four shell pre-checks (`check-jsonb-pattern.sh`,
|
||||
`check-progress-to-stdout.sh`, `check-trailing-newline.sh`,
|
||||
`check-wasm-embedded.sh`) before the runner. Use this mid-branch.
|
||||
2. `bun run typecheck` — `tsc --noEmit` standalone. Fast (~5s on this repo).
|
||||
3. `bun run ci:local` — the full local CI gate from Path A.
|
||||
|
||||
The trap is: writing a new test, running `bun test test/foo.test.ts`,
|
||||
seeing it pass, pushing — and CI's separate typecheck stage rejects an
|
||||
invalid type literal that the runner accepted. Caught one of these
|
||||
shipping the v0.23.2 round-trip E2E (`type: 'reflection'` is not a
|
||||
member of `PageType`). Run `bun run typecheck` once before push, even
|
||||
when only test files changed.
|
||||
The ship-critical IRON RULES stay inline in this file (do NOT relocate them): the
|
||||
Version-locations table above (the 5-file sync + the 3-line VERSION/package.json/CHANGELOG
|
||||
audit), the Conductor branch=workspace rule (above), Post-ship `/document-release` (below),
|
||||
the Privacy + Responsible-disclosure rules (below), and the PR-title-version-first rule
|
||||
(below).
|
||||
|
||||
## Post-ship requirements (MANDATORY)
|
||||
|
||||
@@ -741,294 +718,6 @@ Files that MUST be checked on every ship:
|
||||
|
||||
A ship without updated docs is an incomplete ship. Period.
|
||||
|
||||
## CHANGELOG + VERSION are branch-scoped
|
||||
|
||||
**VERSION and CHANGELOG describe what THIS branch adds vs master, not how we got
|
||||
here.** Every feature branch that ships gets its own version bump and CHANGELOG
|
||||
entry. The entry is product release notes for users; it is not a log of internal
|
||||
decisions, review rounds, or codex findings.
|
||||
|
||||
**Write the CHANGELOG entry at /ship time, not during development.** Mid-branch
|
||||
iterations, review rounds (CEO/Eng/Codex/DX), and implementation detours belong
|
||||
in the plan file at `~/.claude/plans/`, not in the CHANGELOG. One unified entry
|
||||
per branch, covering what the branch added vs the base branch.
|
||||
|
||||
**Never edit a CHANGELOG entry that already landed on master.** If master has
|
||||
v0.18.2 and your branch adds features, bump to the next version (v0.19.0, not
|
||||
editing master's v0.18.2). When merging master into your branch, master may
|
||||
bring new CHANGELOG entries above yours — push your entry above master's
|
||||
latest and verify:
|
||||
|
||||
- Does CHANGELOG have your branch's own entry separate from master's entries?
|
||||
- Is VERSION higher than master's VERSION?
|
||||
- Is your entry the topmost `## [X.Y.Z]` entry?
|
||||
- `grep "^## \[" CHANGELOG.md` shows a contiguous version sequence?
|
||||
|
||||
If any answer is no, fix it before continuing.
|
||||
|
||||
**CHANGELOG is for users, not contributors.** Write like product release notes:
|
||||
|
||||
- Lead with what the user can now **do** that they couldn't before. Sell the capability.
|
||||
- Plain language, not implementation details. "You can now..." not "Refactored the..."
|
||||
- **Never mention internal artifacts**: plan file IDs, decision tags (D-CX-#, F-ENG-#),
|
||||
review rounds, codex findings, subcontractor credits. These are invisible to users.
|
||||
- Put contributor-facing changes in a separate `### For contributors` section at the bottom.
|
||||
- Every entry should make someone think "oh nice, I want to try that."
|
||||
|
||||
**What to omit:**
|
||||
- "Codex caught X that the CEO review missed" — private process detail.
|
||||
- "D-CX-3 split errors/warnings" — tag is meaningless to users; name the feature instead.
|
||||
- "Fix-wave PR #N supersedes #M" — supersede chains belong in PR bodies, not release notes.
|
||||
- "215 new cases, 3 decisions applied, 7 reviews cleared" — these are planning-mode metrics.
|
||||
|
||||
**What to keep:**
|
||||
- The user-facing change: what commands exist now, what flag was added, what behavior fixed.
|
||||
- Numbers that mean something to the user: TTHW, commands that timed out before, detection counts.
|
||||
- Upgrade instructions: `gbrain upgrade` + any manual step if needed.
|
||||
- Credit to external contributors when a community PR was incorporated.
|
||||
|
||||
## CHANGELOG voice + release-summary format
|
||||
|
||||
**IRON RULE: the CHANGELOG describes what the user gets, not how the work
|
||||
happened.** Nobody reading release notes cares that codex caught a bug, that
|
||||
the plan went through CEO + eng review, that the migration was originally
|
||||
numbered v68 and renumbered to v79 during master merge, or that two
|
||||
review rounds caught architectural mistakes. The reader cares what
|
||||
`gbrain brainstorm` does and how to use it. If a fact only exists because
|
||||
of the development process, it does NOT belong in the CHANGELOG.
|
||||
|
||||
**Specifically forbidden in CHANGELOG entries:**
|
||||
|
||||
- Any mention of review processes (CEO review, eng review, codex review,
|
||||
plan-eng-review, outside voice, adversarial review, autoplan, /review).
|
||||
- "What we caught and fixed before merging" sections. Bugs found pre-merge
|
||||
are not changes — they're things that didn't ship.
|
||||
- Plan file references, plan IDs, plan decision tags (D1, D14, D-CDX-3).
|
||||
- Migration version drama ("originally v68", "renumbered to v77", "claimed
|
||||
by parallel waves") — just say "Migration v79 adds X." If the user
|
||||
cares about migration ordering, they read the diff.
|
||||
- Round counts, finding counts, decision counts ("25 findings across 2
|
||||
rounds", "8 architectural decisions", "5/6 expansions accepted").
|
||||
- Names of internal collaborators ("codex caught", "the reviewer flagged",
|
||||
"Claude noticed").
|
||||
- "Plan + reviews" summary bullets. The plan lives in `~/.claude/plans/`;
|
||||
if a future reader wants the backstory they can grep there.
|
||||
- Any wording that frames a shipped feature as a *recovery* from a planning
|
||||
mistake ("the first plan was wrong", "we corrected the approach", "the
|
||||
shipped version supersedes the original design").
|
||||
|
||||
**Smell test:** read the entry as a stranger who has never touched gbrain.
|
||||
If any sentence makes them think "why are you telling me this?", cut it.
|
||||
Every sentence in the release-summary AND in the itemized changes must
|
||||
answer one of three questions: *What can I now do? How do I use it? What
|
||||
should I watch for after I upgrade?*
|
||||
|
||||
Every version entry in `CHANGELOG.md` MUST start with a release-summary section in
|
||||
the GStack/Garry voice — one viewport's worth of prose + tables that lands like a
|
||||
verdict, not marketing. The itemized changelog (subsections, bullets, files) goes
|
||||
BELOW that summary, separated by a `### Itemized changes` header.
|
||||
|
||||
The release-summary section gets read by humans, by the auto-update agent, and by
|
||||
anyone deciding whether to upgrade. The itemized list is for agents that need to
|
||||
know exactly what changed.
|
||||
|
||||
### Release-summary template
|
||||
|
||||
**Iron rule: lead ELI10, get precise after.** The first ~150 words of every entry
|
||||
must be readable by someone who does NOT know gbrain's internals. No file paths,
|
||||
no function names, no internal constants, no acronyms (no "RRF", no "knobsHash",
|
||||
no "MODE_BUNDLES", no "CDX-4"), no jargon that requires reading the codebase to
|
||||
parse. Lead with the user-visible behavior change, in everyday English, like
|
||||
you're explaining it to a smart engineer who has never opened the repo.
|
||||
|
||||
THEN, once the reader knows what shipped and why they'd care, drill into the
|
||||
precise details: real file paths, real function names, real config keys, real
|
||||
numbers. The precision part is required (the entry is also the technical record
|
||||
of what changed), but it lives AFTER the plain-English lead, never before it.
|
||||
|
||||
The shape:
|
||||
|
||||
1. **One-line bold headline.** What changed for the user, in human English. No
|
||||
jargon. No internal terms. Example good: "Your search stops boosting weak
|
||||
pages just because they have a lot of links pointing at them." Example bad:
|
||||
"PostFusionOpts gains floorRatio; KNOBS_HASH_VERSION bumped 2→3."
|
||||
2. **Plain-English opener** (~3-5 sentences). Describe the problem this fixes in
|
||||
everyday terms. Pretend the reader has a brain full of meeting notes and
|
||||
people pages and wants to know if this release helps them. Concrete example
|
||||
beats abstract description.
|
||||
3. **A "How to turn it on" or "How to use it" section** with paste-ready
|
||||
commands. Real flags, real config keys. This is where precision starts.
|
||||
4. **A "What you'd see in a concrete example" or "The X numbers that matter"
|
||||
section** with a table. Use everyday-language column headers ("Page",
|
||||
"Match quality", "Has many backlinks?") even when the underlying mechanism
|
||||
is technical. The table teaches what the feature does without requiring the
|
||||
reader to understand how.
|
||||
5. **A "What's safe to know about" or "Things to watch" section** for caveats,
|
||||
side effects, cache invalidation, mid-deploy notes. Still in plain language.
|
||||
6. **A "What we caught and fixed before merging" section** if the work went
|
||||
through review (CEO/eng/codex/outside-voice). Translate review findings into
|
||||
plain English. "We caught a stale-cache bug" beats "knobsHash() did not
|
||||
include floorRatio in the v=2 hash input."
|
||||
7. **`### Itemized changes`** (precision lives here). File paths, function
|
||||
names, types, constants, line numbers. This section is for engineers who
|
||||
need to know exactly what moved.
|
||||
|
||||
Voice rules (apply throughout):
|
||||
- No em dashes (use commas, periods, "...").
|
||||
- No AI vocabulary (delve, robust, comprehensive, nuanced, fundamental, etc.) or
|
||||
banned phrases ("here's the kicker", "the bottom line", etc.).
|
||||
- Real numbers, real file names, real commands AFTER the ELI10 lead. Not "fast"
|
||||
but "~30s on 30K pages." In the ELI10 lead, "fast enough that you won't
|
||||
notice" or "~30 seconds even on a big brain."
|
||||
- Short paragraphs, mix one-sentence punches with 2-3 sentence runs.
|
||||
- Connect to user outcomes: "the agent does ~3x less reading" beats "improved
|
||||
precision."
|
||||
- Be direct about quality. "Well-designed" or "this is a mess." No dancing.
|
||||
|
||||
**The smell test:** if someone who has never opened gbrain reads the first 150
|
||||
words and walks away knowing what shipped and whether they care, the entry
|
||||
passes. If they need to grep the codebase to follow along, rewrite the lead.
|
||||
|
||||
**Canonical examples in this CHANGELOG:** v0.35.6.0 (floor-ratio gate, written
|
||||
ELI10-lead-first), v0.34.4.0 (embed stale fix wave). Use those shapes when in
|
||||
doubt. Avoid the shape of entries that lead with internal constants or release
|
||||
mechanics; those exist in older history but should not be the model for new
|
||||
work.
|
||||
|
||||
Source material to pull from:
|
||||
- CHANGELOG.md previous entry for prior context
|
||||
- Latest `gbrain-evals/docs/benchmarks/[latest].md` for headline numbers (sibling repo)
|
||||
- Recent commits (`git log <prev-version>..HEAD --oneline`) for what shipped
|
||||
- Don't make up numbers. If a metric isn't in a benchmark or production data, don't
|
||||
include it. Say "no measurement yet" if asked.
|
||||
|
||||
Target length: ~250-350 words for the summary. Should render as one viewport.
|
||||
|
||||
### "To take advantage of v[version]" block (required, v0.13+)
|
||||
|
||||
After the release-summary and BEFORE `### Itemized changes`, every `## [X.Y.Z]`
|
||||
entry MUST include a human-readable self-repair block under the heading
|
||||
`## To take advantage of v[version]`.
|
||||
|
||||
Why: `gbrain upgrade` runs `gbrain post-upgrade` which runs `gbrain apply-migrations`.
|
||||
This chain has a known weak link — `upgrade.ts` catches post-upgrade failures as
|
||||
best-effort (so the binary still works). When that chain silently fails, users end
|
||||
up with half-upgraded brains. The self-repair block gives them a paste-ready
|
||||
recovery path; the v0.13+ `~/.gbrain/upgrade-errors.jsonl` trail + `gbrain doctor`
|
||||
integration close the loop.
|
||||
|
||||
Template (adapt the verify commands per release):
|
||||
|
||||
```markdown
|
||||
## To take advantage of v[version]
|
||||
|
||||
`gbrain upgrade` should do this automatically. If it didn't, or if `gbrain doctor`
|
||||
warns about a partial migration:
|
||||
|
||||
1. **Run the orchestrator manually:**
|
||||
```bash
|
||||
gbrain apply-migrations --yes
|
||||
```
|
||||
2. **Your agent reads `skills/migrations/v[version].md` the next time you interact with it.**
|
||||
[One sentence on whether headless agents need manual action, or whether the
|
||||
orchestrator already handled the mechanical side.]
|
||||
3. **Verify the outcome:**
|
||||
```bash
|
||||
[release-specific verify commands, e.g. `gbrain graph ... --depth 2`]
|
||||
gbrain stats
|
||||
```
|
||||
4. **If any step fails or the numbers look wrong,** please file an issue:
|
||||
https://github.com/garrytan/gbrain/issues with:
|
||||
- output of `gbrain doctor`
|
||||
- contents of `~/.gbrain/upgrade-errors.jsonl` if it exists
|
||||
- which step broke
|
||||
|
||||
This feedback loop is how the gbrain maintainers find fragile upgrade paths. Thank you.
|
||||
```
|
||||
|
||||
**Skip this block** for patches that are pure bug fixes with zero user-facing action
|
||||
(rare). If the release has a schema migration, data backfill, or new feature the
|
||||
user needs to verify, the block is required.
|
||||
|
||||
The v0.13.0 entry in CHANGELOG.md is the canonical example.
|
||||
|
||||
### Itemized changes (the existing rules)
|
||||
|
||||
Below the release summary, write `### Itemized changes` and continue with the
|
||||
detailed subsections (Knowledge Graph Layer, Schema migrations, Security hardening,
|
||||
Tests, etc.). Same rules as before:
|
||||
|
||||
- Lead with what the user can now DO that they couldn't before
|
||||
- Frame as benefits and capabilities, not files changed or code written
|
||||
- Make the user think "hell yeah, I want that"
|
||||
- Bad: "Added GBRAIN_VERIFY.md installation verification runbook"
|
||||
- Good: "Your agent now verifies the entire GBrain installation end-to-end, catching
|
||||
silent sync failures and stale embeddings before they bite you"
|
||||
- Bad: "Setup skill Phase H and Phase I added"
|
||||
- Good: "New installs automatically set up live sync so your brain never falls behind"
|
||||
- **Always credit community contributions.** When a CHANGELOG entry includes work from
|
||||
a community PR, name the contributor with `Contributed by @username`. Contributors
|
||||
did real work. Thank them publicly every time, no exceptions.
|
||||
|
||||
### Reference: v0.12.0 entry as canonical example
|
||||
|
||||
The v0.12.0 entry in CHANGELOG.md is the canonical example of the format. Match its
|
||||
structure for every future version: bold headline, lead paragraph, "numbers that
|
||||
matter" with BrainBench-style before/after table, "what this means" closer, then
|
||||
`### Itemized changes` with the detailed sections below.
|
||||
|
||||
## Version migrations
|
||||
|
||||
Create a migration file at `skills/migrations/v[version].md` when a release
|
||||
includes changes that existing users need to act on. The auto-update agent
|
||||
reads these files post-upgrade (Section 17, Step 4) and executes them.
|
||||
|
||||
**You need a migration file when:**
|
||||
- New setup step that existing installs don't have (e.g., v0.5.0 added live sync,
|
||||
existing users need to set it up, not just new installs)
|
||||
- New SKILLPACK section with a MUST ADD setup requirement
|
||||
- Schema changes that require `gbrain init` or manual SQL
|
||||
- Changed defaults that affect existing behavior
|
||||
- Deprecated commands or flags that need replacement
|
||||
- New verification steps that should run on existing installs
|
||||
- New cron jobs or background processes that should be registered
|
||||
|
||||
**You do NOT need a migration file when:**
|
||||
- Bug fixes with no behavior changes
|
||||
- Documentation-only improvements (the agent re-reads docs automatically)
|
||||
- New optional features that don't affect existing setups
|
||||
- Performance improvements that are transparent
|
||||
|
||||
**The key test:** if an existing user upgrades and does nothing else, will their
|
||||
brain work worse than before? If yes, migration file. If no, skip it.
|
||||
|
||||
Write migration files as agent instructions, not technical notes. Tell the agent
|
||||
what to do, step by step, with exact commands. See `skills/migrations/v0.5.0.md`
|
||||
for the pattern.
|
||||
|
||||
## Migration is canonical, not advisory
|
||||
|
||||
GBrain's job is to deliver a canonical, working setup to every user on upgrade.
|
||||
Anything that looks like a "host-repo change" — AGENTS.md, cron manifests,
|
||||
launchctl units, config files outside `~/.gbrain/` — is a GBrain migration
|
||||
step, not a nudge we leave for the host-repo maintainer. Migrations edit host
|
||||
files (with backups) to make the canonical setup real. Exceptions: changes
|
||||
that require human judgment (content edits, renames that break semantics,
|
||||
host-specific handler registration where shell-exec would be an RCE surface).
|
||||
Everything mechanical ships in the migration.
|
||||
|
||||
**Test:** if shipping a feature requires a sentence that starts with "in
|
||||
your AGENTS.md, add…" or "in your cron/jobs.json, rewrite…", the migration
|
||||
orchestrator should be doing that edit, not the user.
|
||||
|
||||
**The exception is host-specific code.** For custom Minion handlers
|
||||
(host-specific integrations like inbox sweeps or third-party API scanners), shipping them as a
|
||||
data file the worker would exec is an RCE surface. Those get registered in
|
||||
the host's own repo via the plugin contract (`docs/guides/plugin-handlers.md`);
|
||||
the migration orchestrator emits a structured TODO to
|
||||
`~/.gbrain/migrations/pending-host-work.jsonl` + the host agent walks the
|
||||
TODOs using `skills/migrations/v0.11.0.md` — stays host-agnostic, still
|
||||
canonical.
|
||||
|
||||
## Privacy rule: scrub real names from public docs
|
||||
|
||||
@@ -1130,27 +819,6 @@ Applies retroactively: if you see a prior CHANGELOG entry naming attack-surface
|
||||
specifics, scrub it as a small cleanup commit, the same way a stale Wintermute
|
||||
reference gets swept.
|
||||
|
||||
## Schema state tracking
|
||||
|
||||
`~/.gbrain/update-state.json` tracks which recommended schema directories the user
|
||||
adopted, declined, or added custom. The auto-update agent (SKILLPACK Section 17)
|
||||
reads this during upgrades to suggest new schema additions without re-suggesting
|
||||
things the user already declined. The setup skill writes the initial state during
|
||||
Phase C/E. Never modify a user's custom directories or re-suggest declined ones.
|
||||
|
||||
## GitHub Actions SHA maintenance
|
||||
|
||||
All GitHub Actions in `.github/workflows/` are pinned to commit SHAs. Before shipping
|
||||
(`/ship`) or reviewing (`/review`), check for stale pins and update them:
|
||||
|
||||
```bash
|
||||
for action in actions/checkout oven-sh/setup-bun actions/upload-artifact actions/download-artifact softprops/action-gh-release gitleaks/gitleaks-action; do
|
||||
tag=$(grep -r "$action@" .github/workflows/ | head -1 | grep -o '#.*' | tr -d '# ')
|
||||
[ -n "$tag" ] && echo "$action@$tag: $(gh api repos/$action/git/ref/tags/$tag --jq .object.sha 2>/dev/null)"
|
||||
done
|
||||
```
|
||||
|
||||
If any SHA differs from what's in the workflow files, update the pin and version comment.
|
||||
|
||||
## PR title format — version FIRST (IRON RULE)
|
||||
|
||||
@@ -1173,75 +841,6 @@ This applies to `gh pr create` and every `gh pr edit --title`. When `/ship`
|
||||
(or any flow) sets a PR title, the version is the first token. Same rule for the
|
||||
final commit subject that carries the version bump.
|
||||
|
||||
## PR descriptions cover the whole branch
|
||||
|
||||
Pull request titles and bodies must describe **everything in the PR diff against the
|
||||
base branch**, not just the most recent commit you made. When you open or update a
|
||||
PR, walk the full commit range with `git log --oneline <base>..<head>` and write the
|
||||
body to cover all of it. Group by feature area (schema, code, tests, docs) — not
|
||||
chronologically by commit.
|
||||
|
||||
This matters because reviewers read the PR body to understand what's shipping. If
|
||||
the body only covers your last commit, they miss everything else and can't review
|
||||
properly. A 7-commit PR with a body that describes commit 7 is worse than no body
|
||||
at all — it actively misleads.
|
||||
|
||||
When in doubt, run `gh pr view <N> --json commits --jq '[.commits[].messageHeadline]'`
|
||||
to see what's actually in the PR before writing the body.
|
||||
|
||||
## Community PR wave process
|
||||
|
||||
Never merge external PRs directly into master. Instead, use the "fix wave" workflow:
|
||||
|
||||
1. **Categorize** — group PRs by theme (bug fixes, features, infra, docs)
|
||||
2. **Deduplicate** — if two PRs fix the same thing, pick the one that changes fewer
|
||||
lines. Close the other with a note pointing to the winner.
|
||||
3. **Collector branch** — create a feature branch (e.g. `garrytan/fix-wave-N`), cherry-pick
|
||||
or manually re-implement the best fixes from each PR. Do NOT merge PR branches directly —
|
||||
read the diff, understand the fix, and write it yourself if needed.
|
||||
4. **Test the wave** — verify with `bun test && bun run test:e2e` (full E2E lifecycle).
|
||||
Every fix in the wave must have test coverage.
|
||||
5. **Close with context** — every closed PR gets a comment explaining why and what (if
|
||||
anything) supersedes it. Contributors did real work; respect that with clear communication
|
||||
and thank them.
|
||||
6. **Ship as one PR** — single PR to master with all attributions preserved via
|
||||
`Co-Authored-By:` trailers. Include a summary of what merged and what closed.
|
||||
|
||||
**Community PR guardrails:**
|
||||
- Always AskUserQuestion before accepting commits that touch voice, tone, or
|
||||
promotional material (README intro, CHANGELOG voice, skill templates).
|
||||
- Never auto-merge PRs that remove YC references or "neutralize" the founder perspective.
|
||||
- Preserve contributor attribution in commit messages.
|
||||
|
||||
## Checking out PRs from garrytan-agents
|
||||
|
||||
`garrytan-agents` is the AI-authored PR account and is NOT a collaborator on
|
||||
this repo. Its PRs live in a fork, so GitHub Actions triggered by
|
||||
`pull_request` events on those PRs do not receive base-repo secrets. Any CI
|
||||
job that needs `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or similar will fail
|
||||
with empty-env auth errors, regardless of what's set on the base repo. This
|
||||
is a GitHub security default, not a config bug.
|
||||
|
||||
When the user says "check out <PR link>" and the PR is from `garrytan-agents`
|
||||
(or any other non-collaborator fork), move the branch into the base repo
|
||||
before running CI:
|
||||
|
||||
1. `gh pr checkout <N>` — pull down the fork's branch. Note the PR number and
|
||||
head branch name (`gh pr view <N> --json headRefName --jq .headRefName`).
|
||||
2. `git push origin HEAD:<branch-name>` — push the same branch to the base
|
||||
repo (origin points at `garrytan/gbrain`, not the fork). This is the move
|
||||
that gives CI access to secrets.
|
||||
3. `gh pr close <N> --comment "moving to base-repo branch for secret access"`
|
||||
— close the fork PR so the queue stays clean.
|
||||
4. `gh pr create --base master --head <branch-name>` — open the replacement
|
||||
PR from the base-repo branch. **Preserve the original PR's title and body
|
||||
verbatim** (`gh pr view <N> --json title,body`); contributor attribution
|
||||
moves to a `Co-Authored-By:` trailer if needed.
|
||||
|
||||
Why this over alternatives: adding `garrytan-agents` as a collaborator, or
|
||||
flipping the repo-wide "send secrets to fork PRs" toggle, both broaden
|
||||
secret distribution to every fork PR from that account or any fork. Moving
|
||||
the branch keeps secret scope tight to just the one PR being shipped.
|
||||
|
||||
## Skill routing
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ Repo: https://github.com/garrytan/gbrain
|
||||
## Contributing
|
||||
|
||||
- [docs/TESTING.md](https://raw.githubusercontent.com/garrytan/gbrain/master/docs/TESTING.md): Test command tiers, the test-isolation lint (R1-R4), the canonical PGLite block, withEnv, the E2E DB lifecycle, and the file taxonomy. Maintainer-facing.
|
||||
- [docs/RELEASING.md](https://raw.githubusercontent.com/garrytan/gbrain/master/docs/RELEASING.md): Full release + contributor process: pre-ship test requirements, the CHANGELOG voice + release-summary template, the 'To take advantage of vX' block, version migrations, GitHub Actions SHA refresh, PR conventions, community-PR-wave. (Ship IRON RULES stay inline in CLAUDE.md.)
|
||||
|
||||
## Philosophy
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
#
|
||||
# Env overrides (for the guard's own test):
|
||||
# GBRAIN_DOC_GUARD_ROOT repo root to scan (default: script's ../)
|
||||
# GBRAIN_CLAUDE_MD_MAX_BYTES CLAUDE.md hard cap (default: 90000)
|
||||
# GBRAIN_CLAUDE_MD_MAX_BYTES CLAUDE.md hard cap (default: 60000; post-restructure
|
||||
# CLAUDE.md is ~39KB, so this leaves headroom while
|
||||
# staying far below the ~592KB disease state)
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 clean
|
||||
@@ -33,7 +35,7 @@
|
||||
set -uo pipefail
|
||||
|
||||
ROOT="${GBRAIN_DOC_GUARD_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
|
||||
MAX_BYTES="${GBRAIN_CLAUDE_MD_MAX_BYTES:-90000}"
|
||||
MAX_BYTES="${GBRAIN_CLAUDE_MD_MAX_BYTES:-60000}"
|
||||
|
||||
# Reference docs that MUST stay current-state (history-free).
|
||||
REFERENCE_DOCS=(
|
||||
|
||||
@@ -241,6 +241,13 @@ export const SECTIONS: DocSection[] = [
|
||||
path: "docs/TESTING.md",
|
||||
includeInFull: false,
|
||||
},
|
||||
{
|
||||
title: "docs/RELEASING.md",
|
||||
description:
|
||||
"Full release + contributor process: pre-ship test requirements, the CHANGELOG voice + release-summary template, the 'To take advantage of vX' block, version migrations, GitHub Actions SHA refresh, PR conventions, community-PR-wave. (Ship IRON RULES stay inline in CLAUDE.md.)",
|
||||
path: "docs/RELEASING.md",
|
||||
includeInFull: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user