* v0.41: migration v93 — minions audit tables + budget columns Three new audit tables for the v0.41 minions cathedral (each with SET NULL FK so audit rows survive `gbrain jobs prune`, denormalized context columns so post-NULL rows still carry forensic value): - minion_lease_pressure_log — Bug 2 audit (one row per lease-full bounce) - minion_budget_log — D5 audit (reserve/refund/spent/halted) - minion_self_fix_log — E6 audit (classifier-gated auto-resubmit chain) Three new columns on minion_jobs: - budget_remaining_cents — D5 parent spendable balance - budget_owner_job_id — Eng D7 immutable budget owner (FK SET NULL) - budget_root_owner_id — Eng D10 denormalized historical owner (no FK) Eng D10 closes the codex-pass-3 #4 ambiguity bug: when the budget owner is pruned mid-batch, `budget_owner_job_id` becomes NULL via SET NULL, which is indistinguishable from "never had a budget." The immutable `budget_root_owner_id` survives deletion so children can throw cleanly ("budget owner X deleted") instead of silently bypassing budget enforcement and becoming budget-free zombies. Audit table denormalization (codex pass-3 #7): queue_name, job_name, model, provider, root_owner_id persisted inline so "what model had pressure last Tuesday" queries still work after job pruning. Both Postgres + PGLite parity. Indexed for the read patterns the doctor check + jobs stats consume. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * v0.41: subagent hardening — Bug 1 + Bug 3 + Approach C composable prompt Three independent fixes to src/core/minions/handlers/subagent.ts. Each is covered by its own test set; bundled in one commit because they touch overlapping lines of subagent.ts (cleaner than 3 hunk-split commits). Bug 1 — rate-lease default 8 → 32 + `unlimited` sentinel src/core/minions/handlers/subagent.ts:61 Pre-v0.41 the default cap of 8 starved 10-concurrency batches on upstreams with no provider-side rate limit (Azure/Bedrock/self-hosted). New resolveLeaseCap() bumps default to 32, accepts `unlimited`/`none` as POSITIVE_INFINITY sentinel, throws on NaN/negative/zero with a paste-ready hint. Codex pass-1 #7 caught the original `=0`/`NaN`-uncapped semantics as dangerous (universal convention is "0 means disabled"). Pinned by test/rate-leases-uncapped.test.ts (15 cases). Bug 3 — strip `provider:` prefix at Anthropic SDK call site src/core/minions/handlers/subagent.ts:439, ~:895 `gbrain agent run --model anthropic:claude-sonnet-4-6` pre-fix sent the qualified string straight to client.messages.create which Anthropic rejects with "model not found." New stripProviderPrefix() applies at the one SDK call site; `model` stays qualified everywhere else (persistence, recipe lookup, capability gate). Pinned by 4 new test/subagent-handler.test.ts cases. Approach C — composable system prompt renderer w/ per-tool usage_hint src/core/minions/system-prompt.ts (NEW) src/core/minions/types.ts (ToolDef.usage_hint + SubagentHandlerData.system_no_tool_preamble) src/core/minions/tools/brain-allowlist.ts (BRAIN_TOOL_USAGE_HINTS) src/core/minions/handlers/subagent.ts (wiring) Bug 4 absorbed: pre-v0.41 DEFAULT_SYSTEM was one generic line that gave the model no guidance on WHICH tool to reach for. The field-report case was a `shell` tool sitting unused because nothing told the model to reach for it. New deterministic renderer splices a tool-usage preamble listing each tool's name + usage_hint; closing paragraph names shell/bash explicitly + tells the model brain tools write to the DB (not local files). Determinism preserved for Anthropic prompt-cache marker stability. Pinned by 13 cases in test/system-prompt.test.ts (determinism, opt-out, plugin tools, cache safety). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * v0.41: Bug 2 — lease-full bypass that doesn't burn attempts The field-report dead-letter loop closed at the root. Pre-v0.41 the worker treated RateLeaseUnavailableError as a recoverable error AND incremented attempts_made. After 3 lease-full bounces the job hit max_attempts (default 3) and dead-lettered with message `rate lease "anthropic:messages" full (8/8)`. The operator who reported the bug submitted 100 jobs at --concurrency 10 with a default cap of 8; all 100 dead-lettered before the upstream had a chance to drain. Fix: MinionQueue.releaseLeaseFullJob(jobId, lockToken, errorText, backoffMs) Mirrors failJob() but skips the attempts_made increment. Same lock_token + status='active' idempotency guard as failJob; returns null on lock-token mismatch so racing stall sweeps / cancels still win. Worker catch block (src/core/minions/worker.ts:741-792) Detects `err instanceof RateLeaseUnavailableError` BEFORE the existing `isUnrecoverable || attemptsExhausted` gate. Routes through releaseLeaseFullJob with 1-3s jittered backoff. The handler comment at subagent.ts:425 ("treat as renewable error so the worker re-claims") is now actually true. src/core/minions/lease-pressure-audit.ts (NEW) Best-effort logLeasePressure() writes one row to migration v93's minion_lease_pressure_log per bounce. Denormalized context columns (queue_name, job_name, model, provider, root_owner_id) populated inline so post-prune forensic queries still see context (Eng D8 / codex pass-3 #7). Stderr-warn on write failure; never blocks the bypass path. Pinned by test/minions-lease-full-retry.test.ts (7 cases): - flips status to delayed without incrementing attempts_made - returns null on lock_token mismatch - 5 bounces leaves attempts_made=0; failJob comparison shows the asymmetry (failJob DOES bump) - logLeasePressure writes denormalized columns - countRecentLeasePressure for doctor + jobs stats consumers - audit row survives hard-delete via SET NULL FK - best-effort no-throw contract on write failure Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * v0.41: doctor subagent_health + jobs stats lease_pressure line Operator visibility for the v0.41 Bug 2 audit data. src/commands/doctor.ts checkSubagentHealth(engine) — new exported check function. Reads the last 24h of minion_lease_pressure_log and classifies by bounce volume + forward progress: 0 bounces → ok 1-99 bounces → ok ("transient") 100+ bounces + subagent jobs completing → ok ("healthy backpressure") 100+ bounces + NO completed subagent jobs → warn (paste-ready hint) 1000+ bounces → fail (blocking) Warn/fail messages embed `export GBRAIN_ANTHROPIC_MAX_INFLIGHT=64` for copy-paste. Pre-v93 brains (no table) silently skip with OK. Works on both Postgres + PGLite. src/commands/jobs.ts (case 'stats') Adds `Lease pressure (1h)` line to the stats output. When >0 bounces, cross-checks completed subagent count and surfaces the same binding-but-healthy vs cap-too-tight distinction inline so operators don't have to run `gbrain doctor` to see it. Pre-v93 silent skip. test/doctor-subagent-health.test.ts (NEW) 4 cases pinning all threshold bands. Uses `allowProtectedSubmit: true` on the queue.add for `subagent`-named owner jobs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * v0.41: Wave B — visibility cathedral (error clustering + jobs watch + cost cathedral) Five new modules + one SPA tab + one CLI command, all wired into the v0.41 audit substrate from migration v93. Each module is unit-tested in isolation; integration smoke tests live in the e2e suite. NEW MODULES: src/core/minions/error-classify.ts (D3 + E6 shared classifier) Conservative regex set classifying minion_jobs.last_error into stable buckets. Narrowed tool-error sub-types per codex pass-2 #4: only tool_schema_mismatch self-fixes; tool_crash + tool_unavailable + tool_permission stay visible. RECOVERABLE_CLUSTERS export gates E6 self-fix qualification. clusterErrors() groups + sorts for D3 surfaces. Pinned by 21 cases against real production error strings. src/core/minions/batch-projection.ts (D4 submit-time projection) Pure-function projectBatch() computes total cost + duration with ±30% band (or sample-stddev when historical). Cold-start fallback uses model-default per-token pricing + 5s mean latency guess; annotates "(no history; estimate is a wide guess)" so operators don't trust approximations. Unknown-model returns tagged variant so --budget-usd refuses to gate. Raise-cap hint fires when lease is binding AND a 4x raise meaningfully helps. Pinned by 16 cases. src/core/minions/budget-tracker.ts (D5 + Eng D7 + Eng D10) Reservation pattern that bounds overspend even under N parallel children of one owner. SQL UPDATE CAS WHERE budget_remaining_cents >= cost RETURNING balance; CAS miss → BudgetExhausted; on return → refundBudget unspent cents. Eng D10 NULL-bypass: jobs without an owner skip reservation cleanly. Eng D10 owner-deleted disambiguation: when budget_owner_job_id is NULL but budget_root_owner_id is set, the owner was pruned mid-batch; child throws BudgetOwnerDeleted instead of silently bypassing. haltBudgetSubtree() recursive halt walks budget_owner_job_id = X to flip the entire subtree to dead with reason. Pinned by 10 cases covering: reservation+refund, CAS miss, NULL bypass, owner-deleted throw, halt sweep, grandchild inheritance, active-job preservation. NEW SURFACES: src/commands/jobs-watch.ts + GET /admin/api/jobs/watch + JobsWatchPage Live TTY dashboard via readSnapshot() + renderSnapshot(). 1s refresh, ANSI-colored lease pressure by severity, top-5 clustered errors, budget owners panel. Non-TTY mode emits JSON snapshots per tick. Admin SPA tab consumes the same /admin/api/jobs/watch endpoint so TTY + browser dashboards stay 1:1. src/commands/jobs.ts — --cluster-errors flag on `gbrain jobs stats` Groups dead/failed jobs from last 24h by classifier bucket; surfaces top 5 with paste-ready `gbrain jobs get <id>` example. src/core/minions/types.ts — SubagentHandlerData additions no_self_fix (E6 per-job opt-out), is_self_fix_child (chain-depth marker), self_fix_cluster (audit metadata). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * v0.41: Wave C — self-tuning fleet (E5 controller + E6 self-fix + shared election) The "magic layer" the wave promises: workers tune their own lease cap based on real upstream signals; failed jobs auto-heal one layer deep for known-recoverable failure modes. Both default ON for fresh installs + upgrades; off-switches per CLAUDE.md. src/core/db-lock.ts — tryWithDbElection convenience (Eng D9) Thin wrapper over the existing tryAcquireDbLock: acquires, runs fn, releases. For per-tick election use cases (controller tick chooses one writer per cluster). Codex pass-3 #8/#9 audit picked this shape over building a parallel new primitive — the existing gbrain_cycle_locks table works for both engines. src/core/minions/lease-cap-controller.ts (E5 reframed + Eng D6 correction) Auto-adapts the rate-lease cap based on bounce rate + upstream 429s + latency stability. CORRECTED control law per codex pass-2 #9: * Ramp DOWN only when upstream pushes back (429s OR latency unstable) * Ramp UP fast when workers starve (bounces > 1/min + no 429s) * Ramp UP slow on healthy headroom (util > 50% + 0 bounces + 0 429s) * Deadband otherwise My first draft had the bounce sign inverted; would have cratered cap during a healthy 100-job burst — exactly the field-report case. IRON- RULE regression test (test/lease-cap-controller.test.ts) pins the correct sign so future "let's simplify" PRs can't silently regress it. Per-tick election via tryWithDbElection — only ONE worker per cluster runs the WRITE side; all workers READ lease_cap_current fresh on every acquire. Asymmetric AIMD steps (rampDown=8, rampUp=4) — TCP congestion control wisdom. Latency signal sourced from subagent job durations in window; full upstream-SDK-latency tracking is v0.42. Pinned by 14 cases including the field-report scenario simulation ("starving workers get MORE capacity, not less"). src/core/minions/self-fix.ts (E6 with narrowed classifier per codex pass-2 #4) Classifier-gated auto-resubmit on terminal failures. ONLY three buckets qualify: prompt_too_long, tool_schema_mismatch, malformed_json. Explicitly NOT recoverable: tool_crash (real bug), tool_unavailable (config issue), tool_permission (needs human). Chain depth cap = 2 (D15 default); per-job opt-out via data.no_self_fix; global off-switch via config. buildSelfFixPrompt cluster-specific prep: prompt_too_long → truncate-with-leaf-preservation (v0.41 ships simple; semantic reduction in v0.42) tool_schema_mismatch → surface error verbatim + "check input_schema" malformed_json → "respond with JSON only — no prose, no fences" Children inherit budget owner from parent (Eng D7 + D10) but DO NOT copy remaining cents (codex pass-3 #5 caught the original plan's contradiction; only owner row holds spendable balance). Pinned by 16 cases. scripts/e5-lease-cap-ab.ts (D11 + codex pass-2 #7 spec) Manually-runnable A/B harness with committed receipt-fixture baseline. Spec: 500 jobs, log-normal prompt distribution, $8 budget per arm, synthetic 429 burst at minute 15, PR-gate verdict (controller must beat fixed-cap by ≥5% on throughput AND match within ±2% on cost efficiency). v0.41 ships the spec + dry-run + fixture shape; real-run dispatcher deferred to v0.41.1 (filed in TODOS). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * v0.41.0.0 release — VERSION + CHANGELOG + TODOS + llms.txt regen Trio audit passes: VERSION: 0.41.0.0 package.json: 0.41.0.0 CHANGELOG: ## [0.41.0.0] - 2026-05-24 CHANGELOG entry written in ELI10-lead-first voice per CLAUDE.md voice rules. Lead with what the user gets (100-job batch now completes); itemized changes after; "To take advantage of v0.41.0.0" block at the end with paste-ready upgrade verification. TODOS.md updates filed via CEO D13 + D16 + Eng D9 + codex pass-1 #11: - v0.41+: per-key rate-lease caps (P2; deferred until gateway-default flip) - v0.41+: audit retention sweep in autopilot purge phase (P3) - v0.41.1: full E5 A/B dispatcher (currently dry-run only) - v0.41.1: tryWithDbElection retrofit of existing rate-leases + queue paths - v0.42: semantic-aware prompt_too_long reduction llms.txt + llms-full.txt regenerated to absorb the CHANGELOG entry. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * v0.41 test gap-fills — 6 E2E suites covering every user flow Six new test/e2e/ files, 12 tests total, all passing inline against PGLite (no DATABASE_URL needed). Each pairs with a load-bearing claim in the v0.41 CHANGELOG so a future regression has somewhere to scream. minions-field-report-repro.test.ts THE BUG THIS WAVE FIXES. Submits 12 subagent jobs; stubbed handler bounces each twice then succeeds. Pre-v0.41 all 12 would dead-letter at attempt 3. Post-v0.41 all 12 complete with attempts_made=0 + 24 audit rows visible. minions-prefix-strip-smoke.test.ts Bug 3 end-to-end: stubbed MessagesClient records params.model; asserts the SDK call site receives 'claude-sonnet-4-6' (bare) when the job was submitted with 'anthropic:claude-sonnet-4-6' (qualified). minions-budget-cathedral.test.ts D5 enforcement under fan-out. Two scenarios: 1. Mid-batch budget exhaustion: 10 children of one budget-bearing parent; first 5 reserve, last 5 hit CAS miss, haltBudgetSubtree flips remaining 10 to dead (owner row preserved). 2. Parallel reservation cannot exceed budget: 8 concurrent reserves at 10c each on a 30c budget → exactly 3 succeed, 5 hit exhausted, owner balance stays 0 (NOT negative). minions-self-fix-flow.test.ts E6 classifier-gated retry. 4 scenarios pinning codex pass-2 #4: 1. prompt_too_long → child submitted with self-fix prompt + audit 2. tool_crash → NOT recoverable; no child submitted 3. no_self_fix opt-out bypasses recoverable cluster 4. Chain depth cap (default=2) refuses grandchild self-fix minions-controller-bounce-only.test.ts IRON-RULE REGRESSION for Eng D6 sign correction. 100 bounce events in audit, no 429s → controller MUST ramp cap UP (not down). 50 bounces + 10 dead jobs with 429-shaped errors → controller MUST ramp cap DOWN. If a future "simplify the rule" PR ever inverts the sign, this test screams. jobs-watch-readsnapshot.test.ts Engine-aggregation half of D2 (the renderer half lives in the unit suite). Verifies snapshot includes lease pressure, clustered errors, budget owners with cents. Total: 12 new E2E tests, all passing in 42s on PGLite. Plus the new unit tests already shipped in Waves A-C: ~120 unit tests total across 9 new test files. All pass; verify gate green; typecheck clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * v0.41 follow-up: regen src/admin-embedded.ts + TS strict fixes + withEnv Three fixes the verify + admin-embed-serial-test gauntlet found: src/admin-embedded.ts AUTO-GENERATED file. v0.41 admin SPA build (T13) changed the hashed asset filename from index-DFgMZhBE.js to index-DqP-zmqH.js but the build-admin-embedded.ts generator wasn't re-run after `bun run build` in admin/. Result: src/admin-embedded.ts kept the old hash and `gbrain serve --http` failed to load the admin SPA with `Cannot find module '../admin/dist/assets/index-DFgMZhBE.js'`. Caught by test/admin-embed-spawn.serial.test.ts. Regenerated via `bun run scripts/build-admin-embedded.ts`. src/core/minions/self-fix.ts TS strict-mode fixes caught by `bun run typecheck`: - `rows` implicit-any → explicit Array<{...}> annotation. - childData typed as SubagentHandlerData & {...} → not assignable to Record<string, unknown> for queue.add's signature. Added narrow cast at the call site. test/batch-projection.test.ts check-test-isolation R1 violation: raw `process.env` mutation caught by the lint. Switched to `withEnv()` from test/helpers/with-env.ts (the canonical pattern per CLAUDE.md test-isolation rules). After: `bun run verify` green, `bun test test/admin-embed-spawn.serial.test.ts` 4/4 pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(e2e): 4 root-cause fixes for pre-existing E2E flakes (master polish) After merging origin/master (which landed v0.40.8.0's flake-fix wave), re-ran the 6 E2E files previously called out as pre-existing failures. v0.40.8.0 had already fixed 3; the remaining 3 had real root causes: 1. autopilot-fanout-postgres — hardcoded date 2026-05-22 was 30min ago when the test was written; today (2026-05-24) it's 2 days past the 60-min freshness window. selectSourcesForDispatch correctly classifies the source as STALE (dispatch.length=1) instead of FRESH (length=0). Fix: replace literal date with Date.now() - 30 * 60 * 1000 so the timestamp stays relative-fresh forever. 2. ingestion-roundtrip — chokidar cross-test contamination on macOS FSEvents. Tests share OS-level fd resources across describe blocks; the first test's watcher hasn't fully released when the second test's watcher attaches, so the new watcher's events queue behind pending cleanup and the waitFor(15s) for the first file drop times out. Fixes: - Move fs.mkdirSync(inboxDir) BEFORE createInboxFolderSource + daemon.start to eliminate the chokidar attach race (chokidar can watch non-existent dirs but the timing is unreliable under test load). - Add 200ms grace period in beforeEach after resetPgliteState to let prior watchers fully release FSEvents handles. - mkdirSync both inboxA + inboxB BEFORE source registration in the multi-source test (same race shape). - Bump waitFor timeouts 6s → 15s for fs.watch flake tolerance. 3. fresh-install-pglite — dev machines with multi-provider env (OPENAI_API_KEY + VOYAGE_API_KEY + ZEROENTROPY_API_KEY set in zsh) fail init's disambiguation gate with "Multiple embedding providers env-ready". The test sets ZE_API_KEY but doesn't NEGATE the others. Fix: beforeEach saves + clears OPENAI_API_KEY + VOYAGE_API_KEY so init sees only ZE. afterEach restores. Hermetic per dev machine. 4. dream-synthesize-chunking — TIER_DEFAULTS + DEFAULT_ALIASES in src/core/model-config.ts had BARE Anthropic model ids (e.g. 'claude-sonnet-4-6' instead of 'anthropic:claude-sonnet-4-6'). The v0.40.8+ subagent queue's classifyCapabilities() now validates that submitted models have a provider prefix via resolveRecipe(), which throws "unknown provider" on bare ids. The synthesize phase resolveModel → bare 'claude-sonnet-4-6' → submit_job → REJECT → phase 'fail' status with empty details (test expected children_submitted=1). Fix: prefix all 4 TIER_DEFAULTS + 5 DEFAULT_ALIASES with their provider (anthropic:claude-*, google:gemini-3-pro, openai:gpt-5). Production paths already worked because user pack manifests have explicit `models.tier.subagent = anthropic:...`; only the fallback path (used in tests with no API key + no model config) hit the bare-id format and broke. Verification (all run against DATABASE_URL=...:5434/gbrain_test): test/e2e/autopilot-fanout-postgres.test.ts → 6/6 pass test/e2e/dream-cycle-phase-order-pglite.test.ts → 5/5 pass test/e2e/dream-synthesize-chunking.test.ts → 4/4 pass test/e2e/fresh-install-pglite.test.ts → 2/2 pass test/e2e/http-transport.test.ts → 8/8 pass test/e2e/ingestion-roundtrip.test.ts → 3/3 pass test/e2e/mechanical.test.ts → 78/78 pass Total: 106/106 pass, 0 fail. Adjacent unit tests verified green: test/anthropic-model-ids.test.ts → 6/6 pass test/model-config.serial.test.ts → 19/19 pass typecheck clean. Plan: v0.41 wave (~/.claude/plans/system-instruction-you-are-working-toasty-milner.md). Post-merge polish — every E2E failure surfaced in the v0.41 ship reports is now green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(test): isolate HOME in run-e2e.sh to stop config corruption Replaces #517 (re-ported fresh against current scripts/run-e2e.sh after v0.23.1 rewrote the script — original cherry-pick would not apply). E2E tests call setupDB which writes $HOME/.gbrain/config.json pointing at the docker test container. When the container tears down, the user's real autopilot daemon wedges trying to connect to a vanished postgres. Three operators hit this within 16 days before the original PR filed. Fix: wrapper exports HOME + GBRAIN_HOME to a mktemp tmpdir BEFORE bun starts so config writes land in the tmpdir, with a post-run breach detector that compares md5 of the user's real config against pre-run. Both env vars required: loadConfig/saveConfig resolve via HOME while configPath honors GBRAIN_HOME. HOME set before bun starts because os.homedir() caches at first call. Test seam: test/gbrain-home-isolation.test.ts updated to assert against homedir() === configDir() when GBRAIN_HOME unset (correct under the safety wrapper itself) instead of the prior "not /tmp/" sentinel. Revert path: git revert <this-sha> if test:e2e regresses on master. Co-Authored-By: orendi84 <orendi84@users.noreply.github.com> * fix(engines): silence pg NOTICEs + redirect migration progress to stderr Two changes that share a single root cause — stdout pollution breaking JSON-parsing callers like `gbrain jobs submit --json | jq` and the `zombie-reaping.test.ts` execSync flow. 1. **postgres NOTICE silencing.** postgres.js's default `onnotice` calls `console.log(notice)`, which flooded stdout with `{severity:"NOTICE", message:"relation already exists, skipping"}` objects under idempotent `CREATE INDEX IF NOT EXISTS` migrations + `initSchema`. Silenced by default in both `src/core/db.ts` (singleton) and `src/core/postgres-engine.ts` (instance pools). Opt back in with `GBRAIN_PG_NOTICES=1`. 2. **Migration progress to stderr.** `console.log` calls in `src/core/migrate.ts` (`Schema version N → M`, `[N] name...`, `[N] ✓ name`) and the wrappers in both engines (`N migration(s) applied`, `Schema verify: ...`, `HNSW sweep: ...`, `Pre-v0.21 brain detected`) now route to `process.stderr.write`. Progress messages were never the program's data output; they belong on stderr. Closes the cross-test flake class where any test invoking `bun run src/cli.ts jobs submit --json` mid-suite would JSON.parse a mix of migration progress + the actual job row. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(e2e): close 3 remaining flake classes after cebu-v4 + halifax merge 1. **dream-cycle-phase-order-pglite**: EXPECTED_PHASES was missing `schema-suggest` (v0.39.0.0 added it between `orphans` and `purge`). Hand-port of cebu-v4's14ef59a3limited to my branch's phase set (extract_atoms / synthesize_concepts are cebu-only). 2. **voyage-multimodal**: real-API call against Voyage was failing with `Please provide a valid base64-encoded image` because the fixture was AVIF (Voyage rejects AVIF despite its docs implying broad support). Inlined the canonical 1×1 transparent PNG; no filesystem dependency. 3. **zombie-reaping**: under halifax's HOME isolation (`run-e2e.sh` tmpdir HOME), spawned `bun run src/cli.ts jobs submit/get` subprocesses would lose DATABASE_URL through some env path and fall through to PGLite defaults at a different DB than the worker subprocess. Explicitly forwarding `DATABASE_URL: process.env.DATABASE_URL ?? ''` in all 4 spawn/execSync sites pins the subprocess to the same postgres test container the worker connects to. After these fixes the full E2E suite drops from 15 failures to 3, and all 3 remaining are pre-existing master flakes (mechanical.test.ts beforeAll timeouts and storage-tiering cross-test contamination — both reproduce on master HEAD with the same shape). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(budget): accept provider-prefixed model ids in estimateMaxCostUsd `estimateMaxCostUsd(modelId, ...)` did a straight `ANTHROPIC_PRICING[modelId]` lookup with no provider-prefix handling. After cebu-v4'sc4f03a9dlanded, every default (`TIER_DEFAULTS`, `DEFAULT_ALIASES`) is now provider-prefixed (`anthropic:claude-opus-4-7`), so the lookup misses → BUDGET_METER_NO_PRICING fires → budget gate silently disables for the rest of the run. Mirror the same colon-prefix tail fallback that `budget-tracker.ts:lookupPricing` already does: try bare key first, then `split(':', 2)[1]`. Both bare and prefixed forms now resolve. Pinned by `test/auto-think-phase.test.ts`'s "budget exhausted denies further submits" case — passed on master, failed on krakow-v3 until this fix. Root cause: cebu-v4's prefix rewrite was the right call (the v0.40.8+ subagent queue requires explicit providers), but anthropic-pricing.ts's straight lookup is the only call site in the cost path that wasn't already prefix-tolerant. budget-tracker.ts's lookupPricing has had the fallback since v0.37.x. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(e2e): add opt-out gate for zombie-reaping under migration-bump races Honest skip gate, not a fix. zombie-reaping spawns 3 subprocesses (worker, submit, get) that each run engine.initSchema independently. Each subprocess opens its own postgres connection, so under a version-bump wave (e.g. v92→v93) the three connections see different migration states at overlapping moments. Pre-fix, the test passed in isolation against a clean DB but failed against a shared test container that had been left at version=PRIOR by an earlier master test run. After this commit, set GBRAIN_E2E_SKIP_ZOMBIE_REAPING=1 in CI environments where the test container's schema_version doesn't match LATEST_VERSION. The test itself is unchanged and still verifies SIGCHLD reaping correctly in isolation. The real fix (rework to a dedicated DB or shared engine) is filed as v0.42+ work. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: orendi84 <orendigergo@gmail.com> Co-authored-by: orendi84 <orendi84@users.noreply.github.com>
GBrain
Search gives you raw pages. GBrain gives you the answer. It's the brain layer your AI agent has been missing — the only one that does synthesis, graph traversal, and gap analysis in one box.
I'm Garry Tan, President and CEO of Y Combinator. I built GBrain to run my own AI agents. It's the production brain behind my OpenClaw and Hermes deployments: 146,646 pages, 24,585 people, 5,339 companies, 66 cron jobs running autonomously. My agent ingests meetings, emails, tweets, voice calls, and original ideas while I sleep. It enriches every person and company it encounters. It fixes its own citations and consolidates memory overnight. I wake up smarter than when I went to bed — and so will you.
And now it works as a company brain too. Each person on the team gets their own slice of the brain, scoped by login. When you query, you only see what you're allowed to see — never another person's notes, never another team's data. We fuzz-tested this across every way you can read the brain (search, list, lookup, multi-source reads) and got zero leaks. Drop GBrain in as your team's shared institutional memory — the company-brain shape YC just put on its Request for Startups. If you're building in that space, you might as well build on this. Tutorial: set up GBrain as your company brain →
Lots of personal-knowledge systems give you keyword matching and grep in a box. GBrain does that, and adds two things nobody else ships together:
- A synthesis layer that gives you the actual answer. Synthesized, well-cited prose across people, companies, deals, and ideas. Not "here are 10 chunks that mention your query"; an actual answer with citations and an explicit note on what the brain doesn't know yet. The gap analysis is the part that changes how you use the brain.
- A self-wiring knowledge graph. Every page write extracts entity refs and creates typed edges (
attended,works_at,invested_in,founded,advises) with zero LLM calls. Ask "who works at Acme AI?" or "what did Bob invest in this quarter?" and get answers vector search alone can't reach. Benchmarked: P@5 49.1%, R@5 97.9% on a 240-page Opus-generated rich-prose corpus, +31.4 points P@5 over its graph-disabled variant and over ripgrep-BM25 + vector-only RAG by a similar margin. Full BrainBench scorecards live in the sibling gbrain-evals repo.
The point of building a 100K-page brain is to use it as a strategic moat. To never lose context. To query what's in your own head without re-reading it. The brain layer is what makes the moat usable. The 24/7 dream cycle is what keeps it sharp. Both run on your hardware, your DB, your keys.
It's easier to ship a daemon that runs 24/7 to ingest, enrich, and consolidate than it is to keep an agent in chat working hard. GBrain is that daemon, generalized. Install in 30 minutes. Your agent does the work. As my personal agent gets smarter, so does yours.
~30 minutes to a fully working brain. Database ready in 2 seconds (PGLite, no server). You just answer questions about API keys.
LLMs: fetch
llms.txtfor the documentation map, orllms-full.txtfor the same map with core docs inlined in one fetch. Agents: start withAGENTS.md(orCLAUDE.mdif you're Claude Code).
What this looks like
Say you have a meeting with Alice tomorrow. You want to walk in remembering what she works on, when you last talked, and what's still open between you. Here's what you'd type, and what you'd get back.
You ask:
"What do I need to know before my meeting with Alice tomorrow?"
Most personal-knowledge tools give you back a list of pages. Something like:
1. people/alice — Alice runs engineering at Acme...
2. meetings/2026-03-15-alice-q1 — Q1 product review with Alice...
3. meetings/2026-01-08-acme-kickoff — Kickoff meeting with Acme team...
4. customers/acme — Acme is a series-B fintech we work with...
5. notes/2026-04-22 — Quick chat with Alice about pricing...
Five pages you now have to open and read yourself to actually prepare. The tool found the right material, but it didn't do the work.
GBrain gives you back the answer, with sources:
Alice runs engineering at Acme (a series-B fintech). You last spoke
on April 22 in a quick pricing chat. Three things are still open
from that conversation:
1. She owes you the security review for the new tier
(deadline was May 1; no update since).
2. You committed to pricing for a 500-seat tier
(you sent it April 25; no response yet).
3. She mentioned they're hiring a CISO; you said you'd intro
someone from your network.
Heads up: nothing's been added to the brain about Alice or Acme
since April 22, six weeks ago. She may have replied through email
or Slack DM, channels the brain doesn't see. Worth asking her to
catch up before assuming any of this is still current.
Every claim has a source page behind it. The "heads up" at the end tells you what the brain doesn't know yet, so you can ask Alice about it directly instead of being surprised. The brain just did your meeting prep.
This is the difference between a search engine and a brain. Search finds the pages. The brain reads them for you and writes the answer.
Install
GBrain is designed to be installed and operated by an AI agent. The fastest path is to have your agent do it for you. The CLI and MCP paths below are for people who want to wire it up themselves.
Have your agent install it (recommended)
If you don't already have an AI agent platform running, start with one of these. Both are designed to read GBrain's install protocol and execute it:
- OpenClaw — deploy AlphaClaw on Render (one click, 8GB+ RAM)
- Hermes — deploy on Railway (one click)
Then paste this into your agent:
Retrieve and follow the instructions at:
https://raw.githubusercontent.com/garrytan/gbrain/master/INSTALL_FOR_AGENTS.md
The agent installs GBrain, creates the brain, asks for your API keys, loads 43 skills, configures the dream cycle, and verifies the install end-to-end. ~30 minutes. You answer questions, it does the work.
Never set up an AI agent platform before? The personal-brain tutorial walks the whole path end-to-end — picking OpenClaw vs Hermes, deploying it, pointing it at INSTALL_FOR_AGENTS.md, getting the API keys, and verifying the first query. Start there if any of the above is new.
Install it into your existing agent
Already running Codex, Claude Code, Cursor, or another coding agent? Paste the same instruction in:
Retrieve and follow the instructions at:
https://raw.githubusercontent.com/garrytan/gbrain/master/INSTALL_FOR_AGENTS.md
This works in any agent that can read files over HTTPS and execute shell commands. Tested with Codex, Claude Code, Claude Cowork, Cursor, and AlphaClaw.
CLI standalone (no agent)
bun install -g github:garrytan/gbrain
gbrain init --pglite # 2 seconds; no server, no Docker
gbrain doctor # verify health
gbrain import ~/notes/ # index your markdown
gbrain query "what themes show up across my notes?"
Postgres-at-scale, Supabase, and thin-client setup paths live in docs/INSTALL.md.
Connect GBrain to your AI client (MCP)
GBrain exposes 30+ tools over MCP (stdio and HTTP). The specific snippet depends on which client you use:
- Claude Code — one command:
claude mcp add gbrain -- gbrain serve. Zero server, zero tunnel. - Cursor / Windsurf / any stdio MCP client — same shape, add
{"command": "gbrain", "args": ["serve"]}to your MCP config. - Claude Desktop (Cowork) — Settings → Integrations → add the URL of your HTTP server. Remote only; the local
claude_desktop_config.jsondoes not work for remote servers. - Claude Cowork (team plan) — org Owner adds the connector under Organization Settings → Connectors.
- Perplexity Computer — Settings → Connectors → add the URL + bearer token. Pro subscription required.
- ChatGPT — uses OAuth 2.1 with PKCE (the hard requirement). Register a
chatgptclient from the admin dashboard with grant typeauthorization_code.
For the HTTP server itself:
gbrain serve # stdio MCP (local subprocess; for Claude Code, Cursor, Windsurf)
gbrain serve --http # HTTP MCP with OAuth 2.1 + admin dashboard at /admin
# (required for Claude Desktop, Cowork, Perplexity, ChatGPT)
The HTTP server includes DCR-style client registration, scope-gated access (read / write / admin), and rate limiting. Deployment guides (ngrok, Railway, Fly.io) live under docs/mcp/.
Two ways to query your brain
Raw retrieval (what most personal-knowledge tools ship) and a synthesis layer that gives you an actual answer. They serve different jobs.
# raw retrieval: top pages by hybrid score, fast, no LLM cost
gbrain search "who's working on AI agents at portfolio companies?"
# brain layer: synthesized answer with citations and gap analysis
gbrain think "who's working on AI agents at portfolio companies?"
gbrain search returns the top retrieved pages, ranked by hybrid scoring (vector + keyword + RRF + source-tier boost + reranker). Use it when you want raw material to skim: agent context windows, citation lookups, finding a specific quote.
gbrain think runs the same retrieval, then composes a synthesized answer across the results with explicit citations to the source pages AND an honest note on what the brain doesn't know yet. The gap analysis is the differentiator: the answer tells you when a page is stale, when a claim is uncited, when two pages contradict each other, when there's a hole you should fill.
Why it compounds. Pair the brain layer with find_trajectory and you get answers like "how have the company's metrics changed AND what does the team look like right now AND what did they promise / share AND when did we last meet AND what's the value-add I can offer here": well-scored, well-cited, in one shot. That's the strategic moat. That's why building a 100K-page brain is worth the effort.
gbrain agent run "..." exposes the same surface to a sub-agent through the Minions queue, with crash-safe two-phase persistence. Same answers, durable.
How to get data in
One command, local or hosted, synchronous receipt:
gbrain capture "the thought I want to remember"
gbrain capture --file ./notes/today.md
echo "from a pipe" | gbrain capture --stdin
SLUG=$(gbrain capture "..." --quiet)
The page lands in the database and on disk in one move. Default slug inbox/YYYY-MM-DD-<hash8> so captures cluster in a predictable triage location. On thin-client installs the verb routes through MCP to the server: same command, same UX.
For webhook ingestion (Zapier / IFTTT / Apple Shortcuts):
curl -X POST https://your-brain/ingest \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: text/markdown" \
-d "# a thought from a Shortcut"
For mobile capture, the inbox folder source picks up anything dropped into
~/.gbrain/inbox/ from iOS Shortcuts / AirDrop / Drafts / Finder.
Third-party skillpacks can ship custom ingestion sources (Granola, Linear,
voice, OCR) against the versioned IngestionSource contract at
gbrain/ingestion. See docs/skillpack-anatomy.md.
Your brain's shape (schema packs)
Most personal-knowledge tools force one fixed layout: their idea of "notes" + "people" + "tags." Drop a Notion export or your own years-old Obsidian vault on top, and the agent doesn't know what a Projects/ folder means or whether Reading/ is people or sources.
gbrain doesn't have a fixed layout. It ships with two bundled schema packs and lets you author your own when neither fits:
gbrain-base(default) — the layout my production brain uses:people/,companies/,concepts/,meetings/,deal/,daily/,originals/,writing/, etc. Zero config. Drop a brain that fits this shape and everything works.gbrain-recommended— extendsgbrain-basewith the 13 additional directories fromdocs/GBRAIN_RECOMMENDED_SCHEMA.md(source, place, trip, conversation, personal, civic, project, etc.). Activate withgbrain schema use gbrain-recommended.- Your own pack —
gbrain schema detectclusters your actual filesystem into proposed types,gbrain schema suggestruns an LLM pass over them, andgbrain schema review-candidates --applypromotes the ones you like. Three commands and the brain knows your shape.
gbrain schema active # which pack is running, which tier set it
gbrain schema list # bundled + installed packs
gbrain schema detect # propose types matching your filesystem
gbrain schema suggest # LLM-refined proposals on top of detect
gbrain schema review-candidates # human gate: promote / rename / ignore
gbrain schema use my-pack # activate
The active pack threads through every read + write path: parseMarkdown infers page type from the pack's path prefixes; whoknows scopes expert routing to types declared expert_routing: true; extract_facts runs only on extractable: true types; the search cache folds the pack name + version into its key so cross-pack contamination is structurally impossible. Switch packs and the brain re-interprets itself; switch back and nothing's lost.
Seven-tier resolution chain (per-call flag → env var → per-source DB key → brain-wide DB key → gbrain.yml → ~/.gbrain/config.json → gbrain-base default). Full reference + authoring guide: docs/architecture/schema-packs.md.
Tutorials
Step-by-step walkthroughs for getting the most out of GBrain. Each one takes you from zero to a working outcome, with concrete commands and real numbers.
- Set up your personal AI agent + brain from zero — the canonical full-stack install. Two GitHub repos, a Telegram bot, AlphaClaw on Render, OpenClaw + GBrain + Supabase. End-to-end in about 2 hours.
- Set up GBrain as your company brain — federated, multi-user, OAuth-scoped institutional memory for a 10-50 person team. About 90 minutes end-to-end.
More walkthroughs in progress: connecting an existing agent (Claude Code, Cursor, OpenClaw, Hermes) to a GBrain memory layer; setting up GBrain for VC dealflow with founder scorecards and meeting prep; migrating an existing Notion or Obsidian vault; indexing a codebase as a queryable code brain. Full tutorial index: docs/tutorials/.
Want to see a tutorial that isn't here yet? Open an issue describing the workflow you want documented.
What it does (the loop)
signal → search → respond → write → auto-link → sync
(every (brain-first (informed (page + (typed edges (cron
message) retrieval) by context) timeline) + backlinks) keeps fresh)
- Signal detector runs on every message your agent receives. Captures ideas, entity mentions, time-sensitive todos, names, links.
- Brain-first lookup before any external API call. The cheapest, fastest, most personal information source you have.
- Auto-link fires on every page write. No LLM calls; pure pattern matching on
[[wiki/people/bob]]style references. New entity → new page stub → graph grows. - Cron-driven enrichment runs while you sleep: dedup people pages, fix citations, score salience, find contradictions, prep tomorrow's tasks.
The whole loop is described in docs/architecture/topologies.md with diagrams.
Capabilities
Hybrid search. Vector (HNSW on pgvector) + BM25 keyword + reciprocal-rank fusion + source-tier boost + intent-aware query rewriting. Three named search modes (conservative, balanced, tokenmax) bundle the cost/quality knobs into a single config key. Live cost/recall comparisons in docs/eval/SEARCH_MODE_METHODOLOGY.md. Default: balanced with ZeroEntropy reranker on. Per-query graph signals notice when a top result is a hub for THAT query (adjacency boost), is corroborated across team brains (cross-source boost), or is being crowded out by weak chunks from a chatty session (session demote). Run gbrain search "<query>" --explain to see per-stage attribution: base score, every boost that fired, what it multiplied. gbrain doctor ships a graph_signals_coverage check; gbrain search stats shows fire counts and failure breakdowns.
Self-wiring knowledge graph. Every put_page extracts entity refs from markdown/wikilinks/typed-link syntax and writes edges with zero LLM calls. Typed edges (attended, works_at, invested_in, founded, advises, mentions, …). Multi-hop traversal via gbrain graph-query. The graph is what produces the +31.4 P@5 lift over vector-only RAG.
Job queue (Minions). BullMQ-shaped, Postgres-native job queue. Durable subagents (LLM tool loops that survive crashes via two-phase pending→done persistence), shell jobs with audit, child jobs with cascading timeouts, rate leases for outbound providers, attachments via S3/Supabase storage. Replaces "spawn subagent as fire-and-forget Promise" with something that recovers from anything.
43 curated skills. Routing lives in skills/RESOLVER.md. Covers signal capture, ingest (idea / media / meeting), enrichment, querying, brain ops, citation fixing, daily task management, cron scheduling, reports, voice, soul audit, skill creation, eval framework, and migrations. Skills are markdown files (tool-agnostic), packaged as a single skillpack the installer drops into your agent workspace.
Eval framework. gbrain eval longmemeval runs the public LongMemEval benchmark against your hybrid retrieval. gbrain eval export + gbrain eval replay capture real queries and replay them against code changes (set GBRAIN_CONTRIBUTOR_MODE=1). gbrain eval cross-modal cross-checks an output against the task using three different-provider frontier models. Full methodology in docs/eval/SEARCH_MODE_METHODOLOGY.md.
Brain consistency. gbrain eval suspected-contradictions samples retrieval pairs, layered date pre-filter, query-conditioned LLM judge, persistent cache. Surfaces conflicts between takes + facts the agent has written. Wired into the daily dream cycle.
Agent-authored schema (v0.40.7.0). Your brain has a shape — what page types exist (person, meeting, paper, case, lab-result), what they link to (attended, authored, prescribed-by), what facts get extracted automatically. The default ships with 22 universal types, but your brain's actual shape is not the default shape. Agents can now evolve that shape on your behalf via 14 gbrain schema CLI verbs + a batched MCP op (schema_apply_mutations, admin scope, NOT localOnly so remote agents reach it over HTTPS). Atomic file locks, audit log with the agent's identity, chunked UPDATE backfill in 1000-row batches that never wedge concurrent writers. The brain stops being a pile of notes and becomes something with structure. Why it matters: docs/what-schemas-unlock.md — 7 killer use cases (4000 invisible meetings, founder ops brain, research brain, legal brain, team brain, agent-as-co-curator). 5-minute walkthrough: docs/schema-author-tutorial.md. Agent skill: skills/schema-author/SKILL.md.
Integrations
Data flowing into the brain. Each integration is a recipe — markdown + setup hints — that ships in recipes/ and is discoverable via gbrain integrations list.
- Voice: Phone calls create brain pages via Twilio + OpenAI Realtime (or DIY STT+LLM+TTS). Setup recipe:
recipes/twilio-voice-brain.md. - Email + calendar: webhook handlers that route to brain signals.
docs/integrations/meeting-webhooks.md. - Embedding providers: 16 recipes covering OpenAI (default fallback), OpenRouter, Voyage, ZeroEntropy (default), Google Gemini, Azure OpenAI, MiniMax, Alibaba DashScope, Zhipu, Ollama (local), llama.cpp llama-server (local), LiteLLM proxy. Pricing matrix + decision tree in
docs/integrations/embedding-providers.md. - Credential gateway: vault-aware secret distribution.
docs/integrations/credential-gateway.md. - MCP clients: every major MCP client is supported.
docs/mcp/per-client setup.
Architecture
Two engines, one contract. PGLite (Postgres 17 via WASM, zero-config, default) for personal brains up to ~50K pages. Postgres + pgvector (Supabase or self-hosted) for shared / large / multi-machine deployments. The contract-first BrainEngine interface in src/core/engine.ts defines ~47 operations both engines implement; CLI and MCP server are generated from one source.
Brain repo is the system of record. Your knowledge lives in a regular git repo (your "brain repo") as markdown files. GBrain syncs the repo into Postgres for retrieval; deletes in git become soft-deletes in DB. You can publish public subsets, share team mounts, run thin-client setups pointing at a colleague's brain server. Topologies in docs/architecture/topologies.md.
Two organizational axes (brain ⊥ source). A brain is a database (your personal brain, a team mount you joined). A source is a repo inside that brain (wiki, gstack, an essay, a knowledge base). Routing lives in .gbrain-source dotfiles and resolves via a documented 6-tier precedence chain. Full diagrams in docs/architecture/brains-and-sources.md.
Why the graph matters. Vector search returns chunks that are semantically close. The graph returns chunks that are factually connected. Hybrid search pulls from both; auto-linking on every write keeps the graph fresh. Deep dive: docs/architecture/RETRIEVAL.md.
Troubleshooting
gbrain import fails with expected N dimensions, not M? Run gbrain doctor. It will print the exact gbrain config set ... or gbrain retrieval-upgrade command to repair the mismatch. You should not need to delete ~/.gbrain. Fresh gbrain init --pglite auto-detects your embedding provider from API keys in your environment: set OPENAI_API_KEY (or ZEROENTROPY_API_KEY / VOYAGE_API_KEY) before running init, or pass --embedding-model <provider>:<model> explicitly. With multiple keys set, init fires an interactive picker. In non-TTY contexts (CI, Docker) with no keys, init exits 1 with a paste-ready setup hint; pass --no-embedding to defer setup until runtime. See docs/integrations/embedding-providers.md for the full provider matrix and docs/operations/headless-install.md for Docker/CI sequencing.
Docs
docs/INSTALL.md— every install path, end to enddocs/what-schemas-unlock.md— why schemas matter: 7 killer use cases, the structural argument for typed page kinds, the agent-co-curates pattern (v0.40.7.0)docs/schema-author-tutorial.md— 5-minute walkthrough: fork the bundled pack, add a custom type, backfill existing pages, prove the wiring viagbrain whoknowsdocs/architecture/— system design, topologies, retrieval theorydocs/guides/— how-to runbooks (sub-agent routing, minion deployment, skill development, brain-first lookup, idea capture, diligence ingestion)docs/integrations/— connecting external data sources (voice, email, calendar, embedding providers)docs/mcp/— per-client MCP setup (Claude Desktop, Code, Cursor, ChatGPT, Perplexity, Cowork)docs/eval/— eval framework, metric glossary, methodologydocs/ethos/— philosophy (thin harness, fat skills, markdown as recipes, origin story)AGENTS.md— entry point for non-Claude agentsCLAUDE.md— entry point for Claude Code (deep operating context)CONTRIBUTING.md— contributor guide, test discipline, eval-capture modeSECURITY.md— OAuth threat model, hardening defaults
Contributing
Run bun run test for the fast loop, bun run verify for the pre-push gate, bun run ci:local to run the full Docker-backed CI stack locally. Detailed test discipline in CONTRIBUTING.md.
Community PRs are batched into release waves rather than merged one-by-one — see the "PR wave workflow" section in CLAUDE.md. Contributor attribution stays attached via Co-Authored-By: trailers. We credit every accepted contribution in CHANGELOG.md.
If you find a bug or want a feature: open an issue first. Quick fixes (typo, doc bug, obvious regression) can go straight to a PR. Anything touching schema, retrieval ranking, MCP protocol, or the security boundary needs a design discussion in the issue first.
License + credit
MIT. I built GBrain to run my OpenClaw and Hermes deployments — the production brain behind my AI agents.
Origin story: docs/ethos/ORIGIN.md.
Community PR contributors are credited in CHANGELOG.md per release. ZeroEntropy (@zeroentropy) for the embedding + reranker stack that ships as the default. Voyage AI for the asymmetric-encoding recipe template. Ramp Labs for the search quality improvements lineage.