diff --git a/skills/brain-ops/SKILL.md b/skills/brain-ops/SKILL.md index 1cc478f77..ae2769636 100644 --- a/skills/brain-ops/SKILL.md +++ b/skills/brain-ops/SKILL.md @@ -34,6 +34,17 @@ flows through in both directions. > **Convention:** See `skills/conventions/brain-first.md` for the 5-step lookup protocol. > **Convention:** See `skills/conventions/quality.md` for citation and back-link rules. +> **Memory verbs (MEMORY_VERBS v1, gbrain ≥ 0.43).** Over MCP, prefer the five +> frozen memory verbs for the read/write cycle: **`remember(fact, provenance, +> ttl?)`** to save a single durable fact (mandatory provenance; dedupes + +> supersedes), **`recall(query | entity, budget_tokens)`** to read it back +> budget-packed, **`entity(name)`** for a zero-LLM card, **`synthesize(question)`** +> for the expensive cross-page answer, **`forget(id)`** to expire a fact. Use +> `remember` instead of `extract_facts` when you already have ONE formed fact; +> `put_page` / `add_link` / `add_timeline_entry` stay the page/graph write path. +> Fall back to the classic ops when the verbs aren't on the surface. Contract: +> `docs/protocol/MEMORY_VERBS_v1.md`. + ## Contract This skill guarantees: diff --git a/skills/query/SKILL.md b/skills/query/SKILL.md index 91cac630e..7cefc5b29 100644 --- a/skills/query/SKILL.md +++ b/skills/query/SKILL.md @@ -33,6 +33,21 @@ mutating: false Answer questions using the brain's knowledge with 3-layer search and synthesis. +> **Memory verbs (MEMORY_VERBS v1, gbrain ≥ 0.43).** When connected to a brain +> over MCP, prefer the five frozen memory verbs for memory work — they carry +> provenance, evidence, and a server-enforced token budget: +> - **`recall(query | entity, budget_tokens)`** — the budget-packed memory read. +> Use it instead of bare `search` for "what do we know that we SAVED about X". +> - **`entity(name)`** — a zero-LLM person/company/project card (aliases, +> last-touched, open threads, top edges). Use it instead of `get_page` + +> `get_backlinks` when you just need the card. +> - **`synthesize(question)`** — the explicitly-expensive cross-page answer; the +> heavy version of `query`. Reach for it only when the answer must combine +> evidence across pages. +> Fall back to `search`/`query`/`get_page` when the verbs aren't on the surface +> (older brains, or `gbrain serve --surface full`). See +> `docs/protocol/MEMORY_VERBS_v1.md`. + ## Contract This skill guarantees: diff --git a/src/commands/migrations/index.ts b/src/commands/migrations/index.ts index f01cf3fa8..2ee528026 100644 --- a/src/commands/migrations/index.ts +++ b/src/commands/migrations/index.ts @@ -26,6 +26,7 @@ import { v0_28_0 } from './v0_28_0.ts'; import { v0_29_1 } from './v0_29_1.ts'; import { v0_31_0 } from './v0_31_0.ts'; import { v0_32_2 } from './v0_32_2.ts'; +import { v0_43_0 } from './v0_43_0.ts'; export const migrations: Migration[] = [ v0_11_0, @@ -43,6 +44,7 @@ export const migrations: Migration[] = [ v0_29_1, v0_31_0, v0_32_2, + v0_43_0, ]; /** Look up a migration by exact version string. */ diff --git a/src/commands/migrations/v0_43_0.ts b/src/commands/migrations/v0_43_0.ts new file mode 100644 index 000000000..a73e4c0d8 --- /dev/null +++ b/src/commands/migrations/v0_43_0.ts @@ -0,0 +1,33 @@ +/** + * v0.43.0.0 migration — MEMORY_VERBS v1 (Cathedral 1). + * + * PITCH-ONLY. There is NO schema or data migration: the five frozen memory + * verbs (recall/remember/entity/synthesize/forget) ride the existing facts, + * pages, and typed-graph tables. This entry exists solely so `gbrain + * post-upgrade` / the self-upgrade NOTIFY channel actively tells an existing + * install that the verbs landed and how to switch a harness onto them — the + * propagation path the verbs otherwise lacked (the default surface stays + * `full`, so an upgrade alone does NOT steer agents to the verbs). + * + * The orchestrator is a no-op that reports `complete` immediately — + * idempotent by construction (it does nothing), so apply-migrations records + * the ledger row and moves on. + */ + +import type { Migration, OrchestratorOpts, OrchestratorResult } from './types.ts'; + +async function orchestrator(_opts: OrchestratorOpts): Promise { + // No schema/data work — MEMORY_VERBS v1 is a façade over existing tables. + return { version: '0.43.0.0', status: 'complete', phases: [] }; +} + +export const v0_43_0: Migration = { + version: '0.43.0.0', + featurePitch: { + headline: + 'Five memory verbs — recall, remember, entity, synthesize, forget — are now the agent-facing memory protocol (MEMORY_VERBS v1).', + description: + 'Point any MCP harness at `gbrain serve --surface verbs` to expose exactly these five self-describing tools instead of the full op wall: remember(fact, provenance) writes durable facts; recall(query|entity, budget_tokens) returns budget-packed memory; entity(name) is a zero-LLM card; synthesize(question) is the explicitly-expensive cross-page answer; forget(id) expires a fact. Existing `gbrain serve` (full surface) keeps working and now also lists the verbs, but `--surface verbs` is the clean agent surface. Set a default with `gbrain config set mcp_surface verbs`. Verify any endpoint with `gbrain protocol conformance`; see usage with `gbrain protocol stats`. Full contract: docs/protocol/MEMORY_VERBS_v1.md.', + }, + orchestrator, +}; diff --git a/test/apply-migrations.test.ts b/test/apply-migrations.test.ts index 223c28d50..455f772a5 100644 --- a/test/apply-migrations.test.ts +++ b/test/apply-migrations.test.ts @@ -108,7 +108,7 @@ describe('buildPlan — diff against completed + installed VERSION', () => { // autopilot cooperative, v0.16.0 = subagent runtime, v0.18.0 = multi- // source brains, v0.18.1 = RLS hardening, v0.21.0 = Cathedral II // (renumbered from v0.20.0 after master shipped v0.20.x in parallel). - expect(plan.skippedFuture.map(m => m.version)).toEqual(['0.12.0', '0.12.2', '0.13.0', '0.13.1', '0.14.0', '0.16.0', '0.18.0', '0.18.1', '0.21.0', '0.22.4', '0.28.0', '0.29.1', '0.31.0', '0.32.2']); + expect(plan.skippedFuture.map(m => m.version)).toEqual(['0.12.0', '0.12.2', '0.13.0', '0.13.1', '0.14.0', '0.16.0', '0.18.0', '0.18.1', '0.21.0', '0.22.4', '0.28.0', '0.29.1', '0.31.0', '0.32.2', '0.43.0.0']); }); test('already applied → v0.11.0 lands in `applied` bucket, not pending', () => { @@ -148,7 +148,7 @@ describe('buildPlan — diff against completed + installed VERSION', () => { // v0.22.4, v0.28.0, v0.29.1, v0.31.0 were added later; installed=0.12.0 // means they belong in skippedFuture, not pending. v0.11.0 and v0.12.0 // stay pending despite being ≤ installed — that is the H9 invariant. - expect(plan.skippedFuture.map(m => m.version)).toEqual(['0.12.2', '0.13.0', '0.13.1', '0.14.0', '0.16.0', '0.18.0', '0.18.1', '0.21.0', '0.22.4', '0.28.0', '0.29.1', '0.31.0', '0.32.2']); + expect(plan.skippedFuture.map(m => m.version)).toEqual(['0.12.2', '0.13.0', '0.13.1', '0.14.0', '0.16.0', '0.18.0', '0.18.1', '0.21.0', '0.22.4', '0.28.0', '0.29.1', '0.31.0', '0.32.2', '0.43.0.0']); }); test('--migration filter narrows to one version', () => {