docs: sync documentation for v0.46.0.0

The brain-currency wave shipped new user-facing surface the guides did not
carry: the trustworthy autopilot --status exit codes (0/1/2 + paused),
the keyless-safe sync-and-embed chain, and the migrate quiesce fence.

- docs/guides/live-sync.md: keyless clean-refusal note on the embed --stale
  primitive; new "gate on the daemon's heartbeat" verify item with the
  exit-code contract.
- docs/guides/cron-schedule.md: the recommended autopilot health-gate cron
  line (the status classifier already special-cases this monitor line so it
  never reads as an install).
- docs/ENGINES.md: migrate --to now documents the pause-marker mutex, worker
  job-pickup fence, DB-lock drain (GBRAIN_MIGRATE_QUIESCE_SECONDS, default
  300), crash-safe release, and daemon relaunch after the flip.
- docs/operations/headless-install.md: keyless mode's "refuse cleanly" claim
  made concrete — the documented chain exits 0 on a bare stale embed.
- INSTALL_FOR_AGENTS.md Step 7: health-gate bullet + keyless-safe chain note.
- skills/maintain/SKILL.md: autopilot check now teaches the exit-code
  semantics and the --json report fields.
- docs/TESTING.md: inventory entries for the two new harness-tier serial
  suites (real-launchd lifecycle, agent-scheduler shell-chain contract).
- llms-full.txt regenerated (TESTING.md is inlined in the bundle).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-08-12 00:54:18 -07:00
co-authored by Claude Fable 5
parent d2fb2023b8
commit f43e626c71
8 changed files with 88 additions and 3 deletions
+7 -1
View File
@@ -251,7 +251,13 @@ Set up using your platform's scheduler (OpenClaw cron, Railway cron, crontab), o
platform glue entirely with `gbrain autopilot --install` (built-in self-maintaining daemon):
- **Live sync** (every 15 min): `gbrain sync --repo ~/brain && gbrain embed --stale`
— or `gbrain sync --watch` for a continuous loop.
— or `gbrain sync --watch` for a continuous loop. Safe on keyless brains:
a bare `gbrain embed --stale` exits 0 with a stderr note when embeddings
are disabled, so the chain doesn't break.
- **Health gate** (daily): `gbrain autopilot --status` — exit 0 fresh (or
nothing installed), 1 needs attention (stale heartbeat, never ran, or
paused), 2 the daemon took itself out of rotation. Filesystem-only, so it
works during DB outages.
- **Auto-update** (daily): `gbrain check-update --json` (tell user, never auto-install).
- **Dream cycle** (nightly): `gbrain dream` runs the 8-phase overnight maintenance cycle.
Entity sweep, citation fixes, memory consolidation, plus (v0.23+) overnight conversation
+13
View File
@@ -177,6 +177,19 @@ live in `test/postgres-engine-rls-scope.test.ts`.
**Migration:** `gbrain migrate --to supabase` exports everything (pages, chunks, embeddings, links, tags, timeline) and imports into Supabase. `gbrain migrate --to pglite` goes the other direction. Bidirectional, lossless.
The migration and the autopilot daemon do not race: `migrate --to` claims a
cooperative pause marker before touching the target. The marker doubles as a
migration mutex — a second concurrent migrate refuses to run, and a marker
that cannot be written refuses the migration outright. Background job workers
stop picking up new work while it is parked, and the migration waits for
in-flight sync/embed/cycle work and running jobs to actually drain (watching
the DB lock table, capped by `GBRAIN_MIGRATE_QUIESCE_SECONDS` — default 300;
`0` skips the wait). The marker is released even when the migration fails or
is killed; `gbrain autopilot --status` reports `paused` (exit 1) while it is
parked. After a clean flip the daemon detects the engine change on its next
tick and relaunches onto the new engine, and the migration warns if an
exported connection-string env var would override the new config.
### Troubleshooting: startup abort (`RuntimeError: Aborted()`)
**Symptom:** every PGLite-touching command dies at startup with
+2
View File
@@ -175,6 +175,8 @@ Unit tests and what they cover:
- `test/volunteer-context.test.ts` — push-based context core (#2095), hermetic in-memory PGLite: `parseWindow` lenient `user:`/`assistant:` parsing, multi-turn window extraction, confidence-gated volunteering (arm confidences, multi-turn/newest-turn boosts, `min_confidence` gate, max-pages cap), slug-only suppression, privacy (rationales are deterministic templates; synopses pass the takes/facts fence), and the approximate usage-stats join.
- `test/watch-command.test.ts``gbrain watch` push transport (#2095): streaming loop, rolling window, session dedupe, `--json` JSONL shape, `channel: 'watch'` event logging, clean EOF return. Hermetic PGLite + injected line/write deps (no subprocess, no real stdin).
- `test/watch-sigint.serial.test.ts``gbrain watch` SIGINT lifecycle against a real spawned CLI subprocess with a tmpdir brain. SERIAL: parallel unit shards flake on concurrent subprocess spawns (same rationale as `apply-migrations-pglite-spawn.serial.test.ts`).
- `test/autopilot-launchd-lifecycle.serial.test.ts` — autopilot lifecycle behavior, not generated-string assertions: the full install → self-disable → status → reinstall → uninstall arc with `launchctl` replaced by an argv recorder and the generated wrapper executed by a REAL bash against a genuinely deleted repo (every platform), plus a darwin-only fail-SKIP describe against the real launchd under a per-run unique label (`GBRAIN_AUTOPILOT_LABEL`) so it can never collide with — or tear down — a real install on the host. Serial: spawns subprocesses and pins HOME/GBRAIN_HOME for the whole file.
- `test/agent-scheduler-contract.serial.test.ts` — the documented external agent-scheduler shell chain (`gbrain sync --repo X && gbrain embed --stale`, live-sync.md / INSTALL_FOR_AGENTS.md Step 7) driven end-to-end through a real `/bin/sh` against a keyless PGLite brain: the `&&` short-circuit IS the contract (argv arrays can't exercise it), the keyless bare stale embed exits 0, and the pull-failure case that must break the chain does. Anti-vacuity: the fixture commits a real page and every read-back asserts pages >= 1. Serial: real spawned CLI + tmpdir HOME.
- `test/cli-format-volunteer.test.ts``formatResult`'s `volunteer_context` human rendering: pointer lines with confidence/arm/rationale, the empty-result message, the approximate stats summary.
- `test/config.test.ts` — config redaction.
- `test/files.test.ts` — MIME/hash.
+6
View File
@@ -65,6 +65,12 @@ For scheduling `sync` + `embed --stale` specifically, the home doc is
# Brain health — weekly Mondays at 6 AM
0 6 * * 1 gbrain doctor --json >> /tmp/gbrain-health.log 2>&1 && gbrain embed --stale
# Autopilot health gate — daily at 7 AM. The exit code is the signal:
# 0 fresh (or nothing installed), 1 needs attention (stale heartbeat,
# never ran, or paused), 2 the daemon took itself out of rotation.
# Status is filesystem-only, so it works even during a DB outage.
0 7 * * * gbrain autopilot --status >> /tmp/gbrain-autopilot-health.log 2>&1 || your-notify "gbrain autopilot needs attention"
# Dream cycle — nightly at 2 AM
0 2 * * * /path/to/dream-cycle.sh
```
+13
View File
@@ -51,6 +51,10 @@ gbrain sync --repo /path/to/brain && gbrain embed --stale
[spend controls](../operations/spend-controls.md).
- `gbrain embed --stale` -- backfill embeddings for any chunks that don't have
them. Safety net for large syncs (>100 files) or prior `--no-embed` runs.
On a keyless brain (installed with `--no-embedding`), a bare stale embed
refuses cleanly — exit 0 with a stderr note — so this chain is safe to
schedule on keyless installs; keyword search keeps working. Explicit embed
requests (a slug, `--slugs`, `--all`) still exit 1 on a keyless brain.
- `gbrain sync --watch --repo <path>` -- foreground polling loop, every 60s
(configurable with `--interval N`). Embeds inline for small changesets. Exits
after 5 consecutive failures, so run under a process manager or pair with a
@@ -178,6 +182,15 @@ vars — incident-time escape hatches, not everyday knobs.
`gbrain embed --stale` isn't running after sync, leaving chunks invisible
to vector search.
4. **Gate on the daemon's heartbeat.** If the built-in daemon runs your sync
(`gbrain autopilot --install`), wire your scheduler's health check to
`gbrain autopilot --status`. The exit code is the signal: 0 fresh (or
nothing installed), 1 needs attention (stale heartbeat, never ran, or
paused by a migration), 2 the daemon took itself out of rotation.
`--json` emits the full report, including `heartbeat_age_seconds`. Status
reads only the filesystem — no database connection — so it keeps working
during the exact outages it exists to diagnose.
---
*Part of the [GBrain Skillpack](../GBRAIN_SKILLPACK.md).*
+1 -1
View File
@@ -61,7 +61,7 @@ The runtime `gbrain init --force` re-runs the init flow against the now-populate
## Pattern 3: No key, ever (keyless mode)
`--no-embedding` isn't only a deferral — it's also the install shape for **keyless mode**, a first-class supported end state (not a broken one). With zero provider keys, gbrain runs keyword-only (BM25) search and takes memory from agent-authored `## Facts` fences and write ops; embedding and extraction paths refuse cleanly instead of failing silently.
`--no-embedding` isn't only a deferral — it's also the install shape for **keyless mode**, a first-class supported end state (not a broken one). With zero provider keys, gbrain runs keyword-only (BM25) search and takes memory from agent-authored `## Facts` fences and write ops; embedding and extraction paths refuse cleanly instead of failing silently. Concretely: the documented always-current chain (`gbrain sync --repo <path> && gbrain embed --stale`) is safe to schedule on a keyless brain — a bare stale embed exits 0 with a stderr note instead of breaking the chain, while explicit embed requests (a slug, `--slugs`, `--all`) still exit 1.
```dockerfile
FROM oven/bun:1
+39 -1
View File
@@ -1264,7 +1264,13 @@ Set up using your platform's scheduler (OpenClaw cron, Railway cron, crontab), o
platform glue entirely with `gbrain autopilot --install` (built-in self-maintaining daemon):
- **Live sync** (every 15 min): `gbrain sync --repo ~/brain && gbrain embed --stale`
— or `gbrain sync --watch` for a continuous loop.
— or `gbrain sync --watch` for a continuous loop. Safe on keyless brains:
a bare `gbrain embed --stale` exits 0 with a stderr note when embeddings
are disabled, so the chain doesn't break.
- **Health gate** (daily): `gbrain autopilot --status` — exit 0 fresh (or
nothing installed), 1 needs attention (stale heartbeat, never ran, or
paused), 2 the daemon took itself out of rotation. Filesystem-only, so it
works during DB outages.
- **Auto-update** (daily): `gbrain check-update --json` (tell user, never auto-install).
- **Dream cycle** (nightly): `gbrain dream` runs the 8-phase overnight maintenance cycle.
Entity sweep, citation fixes, memory consolidation, plus (v0.23+) overnight conversation
@@ -2230,6 +2236,19 @@ live in `test/postgres-engine-rls-scope.test.ts`.
**Migration:** `gbrain migrate --to supabase` exports everything (pages, chunks, embeddings, links, tags, timeline) and imports into Supabase. `gbrain migrate --to pglite` goes the other direction. Bidirectional, lossless.
The migration and the autopilot daemon do not race: `migrate --to` claims a
cooperative pause marker before touching the target. The marker doubles as a
migration mutex — a second concurrent migrate refuses to run, and a marker
that cannot be written refuses the migration outright. Background job workers
stop picking up new work while it is parked, and the migration waits for
in-flight sync/embed/cycle work and running jobs to actually drain (watching
the DB lock table, capped by `GBRAIN_MIGRATE_QUIESCE_SECONDS` — default 300;
`0` skips the wait). The marker is released even when the migration fails or
is killed; `gbrain autopilot --status` reports `paused` (exit 1) while it is
parked. After a clean flip the daemon detects the engine change on its next
tick and relaunches onto the new engine, and the migration warns if an
exported connection-string env var would override the new config.
### Troubleshooting: startup abort (`RuntimeError: Aborted()`)
**Symptom:** every PGLite-touching command dies at startup with
@@ -2859,6 +2878,10 @@ gbrain sync --repo /path/to/brain && gbrain embed --stale
[spend controls](../operations/spend-controls.md).
- `gbrain embed --stale` -- backfill embeddings for any chunks that don't have
them. Safety net for large syncs (>100 files) or prior `--no-embed` runs.
On a keyless brain (installed with `--no-embedding`), a bare stale embed
refuses cleanly — exit 0 with a stderr note — so this chain is safe to
schedule on keyless installs; keyword search keeps working. Explicit embed
requests (a slug, `--slugs`, `--all`) still exit 1 on a keyless brain.
- `gbrain sync --watch --repo <path>` -- foreground polling loop, every 60s
(configurable with `--interval N`). Embeds inline for small changesets. Exits
after 5 consecutive failures, so run under a process manager or pair with a
@@ -2986,6 +3009,15 @@ vars — incident-time escape hatches, not everyday knobs.
`gbrain embed --stale` isn't running after sync, leaving chunks invisible
to vector search.
4. **Gate on the daemon's heartbeat.** If the built-in daemon runs your sync
(`gbrain autopilot --install`), wire your scheduler's health check to
`gbrain autopilot --status`. The exit code is the signal: 0 fresh (or
nothing installed), 1 needs attention (stale heartbeat, never ran, or
paused by a migration), 2 the daemon took itself out of rotation.
`--json` emits the full report, including `heartbeat_age_seconds`. Status
reads only the filesystem — no database connection — so it keeps working
during the exact outages it exists to diagnose.
---
*Part of the [GBrain Skillpack](../GBRAIN_SKILLPACK.md).*
@@ -3063,6 +3095,12 @@ For scheduling `sync` + `embed --stale` specifically, the home doc is
# Brain health — weekly Mondays at 6 AM
0 6 * * 1 gbrain doctor --json >> /tmp/gbrain-health.log 2>&1 && gbrain embed --stale
# Autopilot health gate — daily at 7 AM. The exit code is the signal:
# 0 fresh (or nothing installed), 1 needs attention (stale heartbeat,
# never ran, or paused), 2 the daemon took itself out of rotation.
# Status is filesystem-only, so it works even during a DB outage.
0 7 * * * gbrain autopilot --status >> /tmp/gbrain-autopilot-health.log 2>&1 || your-notify "gbrain autopilot needs attention"
# Dream cycle — nightly at 2 AM
0 2 * * * /path/to/dream-cycle.sh
```
+7
View File
@@ -195,6 +195,13 @@ Verify autopilot is running:
```bash
gbrain autopilot --status
```
The exit code is trustworthy for gating: 0 fresh (or nothing installed),
1 needs attention (stale heartbeat, never ran, or paused by a migration),
2 the daemon disabled itself (its repo path vanished). `--json` emits the
full report (`state`, `heartbeat_age_seconds`, `paused_reason`,
`disabled_reason`). Status reads only the filesystem, so it works even
when the database is down.
If not running, install it:
```bash
gbrain autopilot --install --repo ~/brain