* feat(verbs): MEMORY_VERBS v1 core — five frozen verbs over existing machinery recall extended in place (G1B additive superset: protocol_version + string fact_id/provenance on every response; query arm via cheap-hybrid with keyword-only degradation when no embedding provider; op-layer budget packing facts-first via the new generic packToBudget). remember/entity/synthesize/ forget as first-class Operations in src/core/verbs.ts (runtime leaf — TDZ-safe both import directions) with MEMORY VERB descriptions, ToolAnnotations, populated suggestions on every error (verbError + protocol ErrorCodes + additive detail/protocol_version on OperationError.toJSON). writeSingleFact (facts/write-single.ts): zero-LLM single-fact seam reusing the pipeline's dedup; X1 deterministic supersession (same entity+kind, similar, text differs -> supersedeId / fence expire+link); validUntil threaded through FenceInputFact (was silently dropped). buildEntityCard (verbs/entity-card.ts): reflex resolution arms + parallel depth-1 reads, per-arm degradation on pre-page_aliases brains, near-miss suggestions with create_safety. runThink gains additive usage aggregation; synthesize converts the no-LLM graceful result to the unavailable protocol error and prices the cost block via canonical model-pricing. RESPONSE_SCHEMAS registry + ERROR_SCHEMA for the conformance kit. Cathedral 1 stage 1/4 (#cathedral-1) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(mcp): MEMORY_VERBS v1 surface mode + fail-closed dispatch + usage sidecar gbrain serve --surface verbs|full (config mcp_surface registered in the merge allowlist; default full — existing installs unchanged). Enforcement is two-layer and fail-closed: filtered ListTools AND dispatchToolCall's new allowedOps set, applied on stdio + BOTH HTTP paths (serve-http.ts OAuth and the second http-transport.ts). ToolAnnotations passthrough in buildToolDefs + the HTTP inline mapper, emitted only when an op defines them (byte-stability for existing tools). Verb validation/internal errors speak the protocol envelope (suggestion + protocol_version) at the dispatch layer. E4 observability: per-verb JSONL sidecar (usage-log.ts — local only, never uploaded; O_APPEND line-atomic, lock-free 10MB rotation) written from dispatch so param-validation failures count; brain_id via gbrainPath; doctor gains the memory_verbs_usage check. CLI: human-readable rendering for remember/entity/ synthesize with trailing --json escape; gbrain recall gains --query + --budget-tokens routed through the recall OP (same arm MCP exercises) with the budget footer; the forget verb carries no cliHint (CLI_ONLY forget dispatches first and would shadow it). Cathedral 1 stage 2/4 (#cathedral-1) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(protocol): gbrain protocol — schemas, conformance kit, stats + TTHW gbrain protocol [--json] emits the live verb input schemas + the hand-authored RESPONSE_SCHEMAS + error contract + versioning policy. gbrain protocol conformance certifies ANY MCP endpoint (default: self-spawned stdio; --target http://...[--token] or a stdio command) against the embedded fixture set — shape/enum/behavior/round-trip only, deterministic; entity-page cases seed via put_page when available and skip honestly on verbs-only targets; synthesize is cost-gated behind --synthesize (asserts the clean unavailable error on key-less CI). Fixtures double as BrainBench seeds (test/fixtures/memory-verbs/cases.json mirror). Self-certification passes 23/23 live. gbrain protocol stats [--days N]: per-verb calls/error-rate/latency, budget drops, entity hit rate, and measured TTHW (init stamps protocol_installed_at; delta to the sidecar's first verb call) — local JSONL only, never uploaded. init epilogues print the 3-command quickstart (mcp add --surface verbs + key-free resurrection demo) with the visibility consent line. entity-card fix: raw namespaced-slug input now matches exactly (slugify flattens slashes). Cathedral 1 stage 3/4 (#cathedral-1) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test+docs(protocol): conformance suite, p99 gate, MEMORY_VERBS_v1 doc, funnel test/memory-verbs-conformance.test.ts: 26 tests through dispatchToolCall — G1B superset regression (legacy fields byte-equal, additions allowed), budget math incl. budget<first-item, keyword degradation (never an error), remember provenance/ttl-trap/null-echo, remote round-trip via the world default + private facts hidden, entity card schema-validated with the chat gateway rigged to throw (zero-LLM guard) + all arms + fence test, synthesize [EXPENSIVE + annotations + clean unavailable, forget idempotency/not_found, writeSingleFact X1 supersession via the embed-transport seam + degraded dedup, the F3 negative self-test (the runner FAILS lying servers: dropped fields, bad enums, re-typed ids), fixture-mirror drift guard. test/mcp-surface.test.ts: verbs=exactly 5, full=identity, dispatch-layer fail-closed, strict flag parsing. test/entity-card-perf.slow.test.ts: 20K pages/100K links/30K aliases/40K facts — measured p99 22.9ms vs the 100ms contract + a recalibrated 50x ratio guard; wired into the CI perf job along with stdio self-certification (23/23 CONFORMANT live). tool-defs byte- stability test now pins per-op: ops WITHOUT annotations keep the exact pre-v1 shape. docs/protocol/MEMORY_VERBS_v1.md: the frozen contract — envelopes, error codes, additive-forever policy, ttl forms (P30D rejected), status-not- status_text, surface modes + why default full, per-harness installs, consent line, conformance pass criteria + copyable --target examples, local-only stats privacy, 200K manual bench recipe. README quickstart + docs/mcp pages moved to --surface verbs with the claude-not-found recovery; llms-config registered + bundles rebuilt; KEY_FILES entries for the 7 new modules. Cathedral 1 stage 4/4 (#cathedral-1) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(verbs): verify-gate compliance — test seam, allow-comment placement, import hygiene usage-log gains __setUsageLogPathForTests so the verb tests redirect the sidecar without mutating process.env.GBRAIN_HOME (test-isolation lint); the gbrain-allow-direct-insert rationale moves onto the insertFact call line (system-of-record guard greps per-line); protocol.ts drops its unused `operations` import (operations-filter-bypass guard — operationsByName only). The synthesize unit test now drives the chat-transport seam (deterministic success envelope + priced cost block, zero real API spend); the keyless `unavailable` conversion stays covered end-to-end by the CI conformance step, which runs credential-free. Cathedral 1 verify pass (#cathedral-1) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(verbs): close 3 ship-review P1s — forget cross-source, entity backlink leak, conformance exit code Pre-landing review (codex, on the committed diff) caught three P1s the plan-stage reviews flagged only in the abstract: P1.1 trust boundary — forget expired by GLOBAL fact id with no source/visibility scope: a remote caller in source A could expire facts in source B (incl. private) by guessing ids. forgetFactInFence gains sourceId + worldOnly opts (scope-check before any state inspection; out-of-scope → not_found, no existence leak); the forget verb passes ctx.sourceId + worldOnly=remote. P1.2 source isolation — entity card incoming edges + backlink_count leaked across sources: getBacklinks(slug,{sourceId}) scopes only the TARGET page and getBacklinkCounts has no source param, so a foreign-source page's slug surfaced in a same-named entity's card. Replaced both with a both-sides-scoped query (f.source_id = t.source_id = entity source, mentions excluded) inside the card module — no engine-interface change. P1.3 CLI exit code — protocol conformance/unknown-subcommand set process.exitCode directly, which the PGLite/WASM force-exit seam ignores (it reads the gbrain-owned setCliExitVerdict). A NOT CONFORMANT target printed the banner but exited 0 — CI would green-light a non-conformant server. Now routes through setCliExitVerdict; proven: unknown subcommand exits 1. Regression tests: cross-source forget → not_found + foreign fact stays active; remote can't forget a private fact; entity card omits foreign-source backlinks from both edges and the count. Cathedral 1 ship-review fixes (#cathedral-1) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * v0.43.0.0 feat(mcp): MEMORY_VERBS v1 — frozen five-verb memory protocol + conformance kit (cathedral 1) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: surface --surface verbs in local-stdio quickstart paths for v0.43.0.0 The MEMORY_VERBS v1 quickstart flag (gbrain serve --surface verbs) was added to the README quickstart, CLAUDE_CODE.md, and CODEX.md during the build but three other docs that show the local-stdio wire-up still presented bare `gbrain serve`: the connect-coding-agent Path B walkthrough (the doc the README links to), INSTALL.md, and DEPLOY.md's Local stdio path. Brought them in line so the five-verb surface is consistent across every local-quickstart entry point. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(doctor): assign memory_verbs_usage check to the SKILL category set The new memory_verbs_usage doctor check (Cathedral 1, E4) was added without a category, tripping the doctor-categories drift guard (every check name must belong to exactly one category set). It's an agent-capability adoption signal, a sibling of retrieval_reflex_health — assigned to SKILL_CHECK_NAMES. Cathedral 1 ship-review fix (#cathedral-1) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(verbs): propagate MEMORY_VERBS v1 to existing harnesses on upgrade The verbs shipped reachable + self-describing, but an EXISTING install that upgrades to 0.43 and keeps its skills had no active push toward them: no post-upgrade notice (default surface stays 'full'), and no skill/guidance routing — agents kept calling search/query/get_page/extract_facts. Two additive propagation fixes: - Post-upgrade feature pitch: src/commands/migrations/v0_43_0.ts (pitch-only, no-op idempotent orchestrator — the verbs ride existing tables, no schema/ data migration). Registered in the migrations index so and the self-upgrade NOTIFY channel announce the five verbs + + on any upgrade past 0.43. Verified live: the pitch fires for an install upgrading from 0.42.43.0. - Skill routing: skills/query (memory reads) and skills/brain-ops (read/write cycle) now teach the verbs — recall/entity/synthesize vs search/get_page/ query, remember vs extract_facts, forget — with a fall-back-to-classic-ops note for older brains / full surface. The in-MCP tool descriptions already steered tool-list readers; this adds the narrative layer the audit found missing across all 29 skills. apply-migrations future-list fixtures updated for the new 0.43.0.0 registry entry. No DB migration; no contract change; verbs unaffected. Cathedral 1 propagation (#cathedral-1) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(verbs): green the 3 failing CI shards — 3-seg migration version, hermetic synthesize test, fresh llms Three real CI-shard failures from the propagation commit + master merges: - migrations-registry (shard 10): v0_43_0 used a 4-segment version 0.43.0.0, but the registry enforces 3-segment semver (/^\d+\.\d+\.\d+$/). Changed the migration version to 0.43.0 (the RELEASE stays 0.43.0.0; migrations have always used 3-seg, e.g. 0.32.2). apply-migrations future-list fixtures updated to match. - synthesize conformance test (shard 5): asserted a successful answer via the chat seam, but runThink builds its client through a real-key check (not the seam), so CI (credential-free) took the NO_ANTHROPIC_API_KEY path → the verb's unavailable conversion → isError. Now wraps the call in withEnv with a fake key AND the chat seam, so it's deterministic regardless of ambient credentials. - build-llms (shard 8): the v0.42.44.0 master merge changed an inlined doc; regenerated llms.txt/llms-full.txt. Cathedral 1 CI fixes (#cathedral-1) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(search): steer concept/landscape questions to query — descriptions, docs, lookup chain, CLI nudge (#2416) The search/query routing guidance shipped a stale and backwards model: SEARCH_DESCRIPTION still led with "Keyword search using full-text search" (search has been cheap-hybrid — vector + keyword + RRF, expansion off — since D4/D15), and the mandatory lookup chain in brain-first.md ordered search-first with query only "if search is thin". For concept/landscape questions ("all the X that do Y"), keyword+vector recall always returns something, so the fallback never fires and expansion-recoverable synonym-phrased matches drop silently. - operations-descriptions.ts: fix the stale SEARCH lead (cheap-hybrid, no LLM expansion); both constants now route concept/synonym/landscape questions to query, cap the claim honestly (both are top-K — exhaustive enumeration belongs to list_pages), and keep every pinned redirect. - brain-first.md: lookup chain is intent-driven (exact token → search; concept/landscape → query FIRST), cost claims corrected, and the anti-pattern is explicit: a nonzero search count is not a completeness signal. Same sweep in brain-ops/SKILL.md and query/SKILL.md, which duplicated the backwards order. - search-modes.md: decision tree + quick-ref updated to the cheap-hybrid reality, new Tricky Spot #6 (count ≠ completeness), example names moved to placeholder people per the privacy convention. RETRIEVAL.md gets the matching one-liner. - query-intent.ts: looksConceptShaped + conceptNudge — deterministic concept-shape classifier in the existing classifier home, tuned to favor false-negatives; cues owned by other routers (find_experts, salience ops) deliberately excluded. cli.ts prints the hint-only stderr nudge on BOTH result paths (local engine + thin-client routed), --quiet-gated; search stays the cheap hot path (never auto-reroutes). - salience-llm-routing e2e: new concept-phrasings block asserts the descriptions actually route concept questions to query (verified live: 20/20 — all 12 personal-query regressions still route to salience ops, all 8 concept phrasings route to query). - KEY_FILES.md: query-intent entry updated to current state (the old entry pointed at a renamed file); llms bundle regenerated (no diff — entry is link-only). - TODOS.md: MCP-envelope hint follow-up filed (remote agents are the higher-value half; needs a return-contract change kept out of this commit). Verification: typecheck clean; 70 targeted unit tests + 20 live routing evals green; all 24 check:all guards green; failing full-suite shards triaged — think-pipeline.serial.test.ts:434 fails identically on the clean tree (pre-existing on this branch, filed separately), the rest are PGLite parallel-load contention that pass in isolation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(test): pin think's stub-path usage at null per the E2 accounting contract The MEMORY_VERBS [E2] usage-accounting change deliberately moved "no LLM ran" from `undefined` to `null` (the frozen cost-block spelling), but the older #1698 stub-path test still pinned `undefined` and failed on every run of this branch. The protected semantic is unchanged: no fake usage or cost on the stub path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(changelog): cover the #2416 query-steering wave under v0.43.0.0 The 0.43.0.0 entry described only MEMORY_VERBS; the #2416 retrieval-routing wave rides the same release. Adds its user-facing summary and refreshes the release date to the actual ship date. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(protocol): reword so the #3502 docs-lint doesn't read a phantom command Master's docs-lint (landed after this branch forked) scans for `gbrain <verb>` references; the MEMORY_VERBS diagram's "gbrain reference implementation" phrasing parsed as a nonexistent `gbrain reference` command. Post-merge-only failure; both sides were green alone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: update project documentation for v0.43.0.0 Post-ship /document-release drift pass over the MEMORY_VERBS v1 + #2416 query-steering waves: - docs/tutorials/connect-coding-agent.md: the pasteable brain-first protocol still taught the pre-#2416 "Search first" rule and named only full-surface tools; step 1 now routes by question shape (exact tokens -> search, concept/landscape -> query first) and both steps map the five-verb surface names (recall/synthesize/remember). find_experts and query callouts marked with their surface. - README.md + tutorial: "90-tool wall" count refreshed to 110 (the actual operation catalog). - CLAUDE.md: contract-first op count ~90 -> ~110 with the v0.43.0.0 MEMORY_VERBS clause; reference-map row for the memory-verbs protocol / --surface / conformance docs. - TODOS.md: blank line before the v0.42.74.0 section header. - llms-full.txt regenerated (build:llms; freshness test green). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: apply cross-model doc-review fixes for v0.43.0.0 Verified findings from the /document-release Codex pass: - MEMORY_VERBS_v1.md: disclose that conformance WRITES (marker-suffixed seed page + remember/forget facts, write-scope creds, artifacts not auto-deleted); quickstart header says 4 commands because it has 4. - CHANGELOG v0.43.0.0: cost claim scoped per verb (budget/latency/cost block); remember "updates in place" -> supersedes-with-history (what write-single.ts actually does). - DEPLOY.md: legacy bearer fallback works on BOTH engines now (both schemas carry access_tokens per http-transport.ts) — was Postgres-only. - CLAUDE_CODE.md: list_skills/core-tools verify note marked full-surface (on --surface verbs those tools aren't on the surface). - skills/query/SKILL.md: --surface full INCLUDES the verbs; fallback is for pre-0.43 servers only. - skills/brain-ops/SKILL.md: search/query tool labels updated to the #2416 reality (cheap hybrid vs hybrid + LLM expansion). - search-modes.md: stale "keyword search returns chunks" label. - RETRIEVAL.md: note the query op defaults expand:true per call. - Counts: 43 skills -> 52 (README x2, INSTALL), 30 skills -> 52 (CLAUDE.md), "30+ tools over MCP" -> 110 (README). - TODOS.md: filed 2 code-vs-spec follow-ups (recall filter composition + limit cap; synthesize unavailable-mapping breadth) instead of silently editing the frozen contract. - llms-full.txt + skills.lock.json regenerated; freshness guards green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(cli): regenerate the flag registry for the cathedral-1 command set Master's #2185 strict flag validation ships a committed, generated CLI_FLAG_REGISTRY with drift + freshness guards keyed off CLI_ONLY. The merge added this branch's `protocol` command to CLI_ONLY, but the committed registry was generated on master without it, failing CI shard 7's drift guard. Regenerated via `bun run build:flag-registry` on the merged tree (95 commands; picks up `protocol` and the `--surface` help-text mentions from the verbs work). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
13 KiB
MEMORY_VERBS v1 — the memory wire protocol
GBrain's frozen five-verb memory interface over MCP: recall, remember,
entity, synthesize, forget. The contract every harness can rely on the
way every Postgres client relies on the wire protocol — and the contract any
OTHER memory server can implement and certify against
(gbrain protocol conformance --target <endpoint>).
agent (any MCP harness)
│ remember("picked Stripe over Adyen", provenance: "chat 2026-06-11")
▼
five verbs ── recall ── remember ── entity ── synthesize ── forget
│ self-describing envelopes: protocol_version, evidence, provenance,
│ budget meta, cost block, enumerated error codes + a populated fix
▼
your brain (reference implementation: gbrain; any conformant server)
Machine-readable spec: gbrain protocol --json emits the input schemas
from the live operation definitions plus the response-shape registry — doc and
code structurally cannot drift; conformance validates live responses against
the same registry.
Versioning policy (the point of the freeze)
- Every field NAME and its SEMANTICS in v1 are frozen forever — never removed, renamed, or re-typed; meanings never change.
- New OPTIONAL params and new OPTIONAL response fields may be added at any time (additive-forever). A conformant CLIENT must ignore unknown fields; a conformant SERVER must never reject unknown-to-v1 additions it itself ships.
protocol_version(integer, starts at1) rides every verb response and every verb error. It increments ONLY on a breaking change, which by policy requires a newMEMORY_VERBS_v2document — expected never.- Conformance pins a minimum version; certification asserts shape, enum validity, contract behavior, and round-trips — never ranking quality (that is BrainBench's job).
- Enum values are part of the contract. Where an enum's DERIVATION is implementation-defined (noted per field), implementations may improve the derivation without a version bump; the values and their meanings stay fixed.
Install (the 4-command quickstart)
gbrain init --pglite # 2-second local brain
claude mcp add gbrain -- gbrain serve --surface verbs # the five-verb surface
gbrain remember "I prefer dark mode in every editor" --provenance demo --entity people/me
gbrain recall --entity people/me # …now ask your agent in a NEW session
Memories agents save are readable by every agent connected to this brain; pass
visibility: "private"for local-CLI-only facts.
If claude is not found: install Claude Code first, or use a block below.
Codex
codex mcp add gbrain -- gbrain serve --surface verbs
OpenClaw / any stdio MCP host — register the server command
gbrain serve --surface verbs. Remote brains: gbrain serve --http on the
host, then gbrain connect https://host/mcp --token gbrain_xxx --install on
each client.
Surface modes: --surface verbs exposes EXACTLY the five verbs —
advertised list AND dispatch are filtered fail-closed (a hidden op returns
unknown_tool even when called by name). --surface full (the default)
exposes every operation, verbs included. Why default full: verbs is for
agents and quickstarts; full preserves existing advanced tooling. Persist a
default with gbrain config set mcp_surface verbs.
The verbs
recall(query?, entity?, budget_tokens?, since?, session_id?, limit?, …) — read
Retrieve saved facts and (with query) budget-packed page snippets.
entityscopes the FACTS arm;queryruns the hybrid-search arm over pages; both present ⇒ both arms run.since: ISO 8601 date/datetime — filters the FACTS arm only in v1. (The reference implementation also accepts relative phrases like"8 hours ago"as a convenience; only ISO 8601 is part of the frozen contract.)limitis a PER-ARM cap (facts and search results each).budget_tokens: SERVER-side packing — facts pack first (limit-capped one-liners, so search-arm starvation is bounded), search results take the remainder. The estimator is char/4 (±10–15%);budget_usedreports packed tokens,dropped_countwhat didn't fit. Never advisory, never client-side.- No embedding provider configured? The search arm degrades to keyword-only
and the response notes
search_degraded— never an error.
Response — an additive SUPERSET of the pre-v1 facts envelope on EVERY call (all legacy fields unchanged; JSON consumers ignore additions):
| field | type | semantics |
|---|---|---|
protocol_version |
int | always present (every verb, every call) |
facts[] |
array | legacy fact fields unchanged, PLUS per fact: fact_id (opaque STRING — the value forget accepts; the legacy numeric id stays for pre-v1 consumers) and provenance (the stored source attribution) |
total |
int | count of facts returned |
results[] |
array | search arm only: slug, title, chunk, evidence, create_safety, provenance (origin page slug) |
search_degraded |
string? | present when keyword-only fallback fired |
budget_tokens / budget_used / dropped_count |
int? | present when budget_tokens was passed |
evidence (enum, zero-LLM heuristic): alias_hit | exact_title_match |
high_vector_match | keyword_exact | weak_semantic — why each result
matched. create_safety (enum): exists (a page for this already exists)
| probable (likely exists; check before creating) | unknown (no
signal). The derivation of both is implementation-defined and may improve;
the values are frozen.
remember(fact, provenance, ttl?, entity?, kind?, visibility?) — write
Save ONE fact with mandatory attribution.
provenance(REQUIRED, free text ≤500 chars, stored verbatim): e.g."conversation 2026-06-12","user said in chat","import: notes.md". Empty ⇒provenance_requirederror with a fix.entity: set whenever the fact is about a specific person/company/project — entity-scoped recall will not find unattributed facts.ttl: duration shorthand ("30d","12h","45m") or an absolute ISO 8601 timestamp. ISO-8601 DURATIONS (P30D) are rejected with a self-correcting suggestion. Omitted ⇒ never expires.kind:event|preference|commitment|belief|fact(default).visibility:world(DEFAULT — readable by every agent connected to this brain; required for the remote remember→recall round-trip) |private(local CLI reads only). The init quickstart carries the consent line.
Response: { id, status, status_text, entity_slug, valid_until, protocol_version } (+ degraded_dedup: true when no embedding provider —
near-duplicates may insert; dedup and supersession ride embedding similarity).
id— opaque STRING (gbrain serializes integers; another implementation may use UUIDs). Onstatus: "duplicate"it is the EXISTING fact's id.status—inserted|duplicate|superseded. Branch onstatus, never onstatus_text(the human rendering). Supersession is implementation-defined; the reference rule: same entity + same kind + similarity above the dedup threshold + different text = the new fact supersedes the old ("X at acme-example" → "X left acme-example").- Omitted optional inputs echo as
null, never absent.
entity(name) — read, zero LLM, p99 < 100ms
One known person/company/project card. NEVER errors on a miss.
Resolution (frozen precedence): alias > exact title > slug/slug-suffix; ties
break on most-recently-touched. Multi-hit ⇒ best match's card + runners-up in
suggestions. Miss ⇒ found: false + keyword near-misses with
create_safety hints.
Response: { protocol_version, found, latency_ms, card?, suggestions? }.
Card: { entity{slug,title,type}, aka[], summary, last_touched{updated_at, last_retrieved_at, last_timeline_date}, open_threads[], edges[], backlink_count, active_fact_count }.
summarypasses the same privacy fences asget_page(takes + private facts stripped); remote callers never see private facts in the card.open_threads(best-effort in v1): active commitment-kind facts + timeline entries from the last 90 days, capped at 3.edges: top ~10 typed edges, mentions excluded, out-edges first.- The p99 < 100ms promise is op-layer latency (transport excluded), CI-gated on a 20K-page corpus. 200K validation recipe below.
synthesize(question, since?, until?) — read, EXPENSIVE
[EXPENSIVE / SLOW — makes LLM calls, seconds-to-minutes latency, costs money] — the deliberately-priced slow verb. Prefer recall/entity for
lookups; use synthesize only when the answer requires combining evidence
across pages.
Response: { answer, sources[], gaps[], cost{model, input_tokens, output_tokens, usd_estimate}, protocol_version }.
- The
costblock is a BEST-EFFORT AGGREGATE (retries/multi-call flows sum; cache hits may undercount; token fields arenullwhen a provider returns no accounting). Honest signal, not an invoice. - No LLM configured ⇒ the protocol error
unavailablewith a fix — never a fake answer.
forget(id, reason?) — write
Expire a fact by its opaque string id (from remember or
recall.facts[].fact_id — never a page slug). Idempotent: re-forgetting an
already-expired fact returns expired: false (success); unknown id ⇒
not_found. Facts are expired with an audit trail, never deleted.
Response: { id, expired, reason, protocol_version }.
Error contract (uniform across all five verbs)
{ "error": "<code>", "message": "...", "suggestion": "problem + cause + fix",
"detail": "freeform specifics", "protocol_version": 1 }
Codes (coarse on purpose — codes are for branching; detail carries the
story): invalid_params, provenance_required, not_found, scope_denied,
unavailable (a required dependency cannot serve: no API key, gateway down,
model refusal — configure/retry, not a server bug), budget_unsatisfiable
(RESERVED — schema-listed, never returned in v1), internal.
Every verb error carries a POPULATED suggestion. Specific cases: recall on
an empty brain returns empty arrays (success, not an error); auth/scope
failures fail closed via the standard dispatch.
Trust boundary
Verbs are ordinary operations: they inherit fail-closed remote semantics,
OAuth scope enforcement (remember/forget are write-scope), and per-source
isolation on every read. Remote callers see visibility = world facts only.
Conformance + certification
gbrain protocol conformance # self-certify (stdio)
gbrain protocol conformance --target http://localhost:3131/mcp --token gbrain_xxx
gbrain protocol conformance --target "bun run src/cli.ts serve"
gbrain protocol conformance --synthesize # also live-call synthesize
Pass criteria: response SHAPE (required fields, enum validity), CONTRACT
BEHAVIOR (provenance rejected when empty; budget arithmetic consistent;
entity miss ⇒ found:false, not an error; private facts absent from remote
cards; idempotent forget), and ROUND-TRIP (remember → recall by entity — a
plain indexed read, deterministic). It does NOT judge ranking quality.
Entity-card cases need a seedable page (put_page); against verbs-only
targets they skip honestly. --synthesize is cost-gated: with no LLM key it
asserts the clean unavailable error (what CI does); with a key it spends
real tokens.
Conformance is a LIVE test that WRITES: it seeds a marker-suffixed synthetic
entity page (people/conformance-<marker>, when the target exposes
put_page) and writes/expires facts through remember/forget. Point it at
write-capable credentials and a brain you're comfortable leaving those
synthetic artifacts in — they're marker-named for easy cleanup, not
auto-deleted. The fixture set ships as data
(test/fixtures/memory-verbs/cases.json) and seeds BrainBench's
protocol-compliance arm. gbrain's CI certifies its own stdio + HTTP
transports; external certification is best-effort tooling until a second
implementation exists.
Observability (local only)
Every verb call appends one line to
~/.gbrain/integrations/memory-verbs/usage.jsonl — local JSONL only, never
uploaded, stats-only (lock-free rotation may drop lines; POSIX O_APPEND
line-atomic, best-effort on Windows). gbrain protocol stats [--days N]
aggregates per-verb calls, error rate, latency, budget drops, entity hit rate,
and the measured TTHW (install → first verb call, from the
protocol_installed_at stamp). gbrain doctor carries a
memory_verbs_usage health line.
200K-page latency validation (manual recipe)
CI gates entity() p99 < 100ms on a 20K-page corpus
(test/entity-card-perf.slow.test.ts). To validate at 200K, edit the
constants at the top of that file (PAGES = 200_000, LINKS = 1_000_000,
ALIASES = 300_000, FACTS = 400_000) and run
bun test test/entity-card-perf.slow.test.ts --timeout=1800000 — seeding
dominates (~minutes); the measured calls report p50/p99 + the ratio guard.