Files
gbrain/docs/guides/ambient-recall.md
Garry TanandClaude Fable 5 15ecc65b24 v0.45.7.0 feat(mcp,context): ambient recall — context_pack + delta frozen verbs + boundary runtime (#1) (#4028)
* feat(mcp,context): ambient recall — context_pack + delta frozen verbs + boundary runtime (#1)

Two new frozen MEMORY_VERBS (context_pack, delta) on the pull surface + a
Claude Code hook boundary runtime on the push surface, sharing one stateless
assembler core (assembleTurnContext mode: turn|pack|delta) and a keyset
session cursor (migration v126). World-only by default; include_private
gated fail-closed to trusted-local. protocol_version stays 1 (additive
5→7 verbs). Survived three adversarial review waves.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* v0.45.7.0 feat(mcp,context): ambient recall — context_pack + delta frozen verbs + boundary runtime (#1)

Two new frozen MEMORY_VERBS (context_pack, delta) grow the frozen set 5→7
without a wire bump — all seven stamp protocol_version: 1. context_pack
assembles a deterministic, zero-LLM, budget-packed bundle (entity cards +
open threads + hot facts) for a set of standing entities; delta returns
only what changed since a timestamp for cheap heartbeats, with a
per-session keyset cursor for at-least-once delivery. A boundary runtime
wires these into Claude Code lifecycle hooks (SessionStart warm pack,
PreCompact entity banking for post-compaction rehydration); Codex and any
MCP host pull the same verbs at their own boundaries. World-only by
default on all arms; include_private widens only for local trusted
callers. Migration v126 adds session_context_state (additive).

Includes the coverage close-out wave (~55 tests): real-serve compact→
session-start round trip over the live socket, --surface verbs stdio
session pinning exactly 7 tools fail-closed, HTTP-transport verb calls
with per-token cursor isolation, Postgres engine-parity for keyset
pagination + the session-cursor table, migration v126 shape + rewind
test, sub-second latency gates, CLI-level invocations, rendered-protocol
boundary assertions, and a live-Codex boundary-call check. The wave
caught and fixed three real bugs: the delta CLI wedging on first wake
(floating GC promise racing engine teardown), the compact hook probing
the PGLite socket on a Postgres config with a leftover database_path,
and the verbs-surface banner hardcoding a stale verb count.

Also the /document-release sweep: stale "five verbs" → seven across the
protocol doc, README, INSTALL, DEPLOY, the Claude Code MCP guide, and
the query skill; deferred scope filed in TODOS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(release): bump openclaw.plugin.json to 0.45.7.0 — the sixth version location

The #4033 merge auto-resolved the OpenClaw plugin manifest at master's
version while the trio moved to 0.45.7.0, failing the manifest drift test
on CI shard 4. Register the file in CLAUDE.md's version-locations table
(five → six) so every future ship and merge re-bumps it with the trio.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 10:56:11 -07:00

5.2 KiB

Ambient recall — placing retrieval at session boundaries

Long-lived agent harnesses (your OpenClaw, Hermes, Codex, Claude Code) get the most value from the brain not on every message, but at the moments where a fresh question rarely fires on its own: session start, right after compaction, and on heartbeats. This guide is the Pareto frontier of where to place each verb.

The bottleneck for a long-lived agent is not retrieval quality — the corpus answers well when asked. It is placement: the misses come from moments when no question fires. Two frozen verbs close that gap with 2-3 deterministic calls per session instead of per-message overhead.

The frontier — which verb goes where

Moment Call Why Cost
Any entity-bearing message entity(name) Zero-LLM, p99 < 100ms. Safe to run synchronously almost anywhere. negligible
Session start context_pack(entities, budget_tokens) Warm the thread's 1-3 standing entities before the first message. zero-LLM, sub-second
After compaction context_pack(entities, budget_tokens) Rehydrate the verbatim detail the summary dropped. zero-LLM, sub-second
Heartbeat / periodic wake delta(session_id, budget_tokens) "What changed since my last wake" in O(changes), deduped. zero-LLM, sub-second
Explicit memory question recall(query | entity, budget_tokens) The budget-packed read for "what do we know that we SAVED about X". sub-second (+1 embedding if query)
Answer needs cross-page reasoning synthesize(question) LLM-backed. Never on a hot or ambient path. seconds-to-minutes, $$

Observed shape: per-message retrieval beyond entity cards adds latency faster than insight; session-start packs and post-compaction rehydration are nearly pure win. See the per-verb latency table in docs/protocol/MEMORY_VERBS_v1.md.

Two integration surfaces

  • Pull (works everywhere, including Codex + Postgres/Supabase): the harness calls context_pack / delta over MCP (they are on --surface verbs) or the CLI (gbrain context-pack, gbrain delta) at the boundary and injects the returned text (or renders the structured arms). This is the portable path — no hooks required. It is the primary path for Codex (which has no hooks) and for Postgres brains (which have no local IPC socket).
  • Push (PGLite + Claude Code): the bundled hook framework fires automatically at SessionStart (injects a warm pack — including the post-compaction re-entry, source=compact) and PreCompact (banks the window's standing entities for that rehydration pack). Heartbeat deltas are the PULL path — there is deliberately no push heartbeat; call delta per the HEARTBEAT cadence table.

Visibility — world-only by default

A pack is injected into an agent context window that may be logged or synced to a cloud model, so every arm is world-visibility by default. To pull private facts in, pass include_private — and it is honored ONLY for trusted-local callers (remote === false, i.e. the CLI/hook path). A remote MCP caller never widens, even if it asks (fail-closed). When it does widen, all arms widen together, so a pack is never a mix of private facts beside world-stripped synopses.

Budgets

Every pack/delta call takes budget_tokens. The server packs highest-priority arms first (cards → facts for packs; pages → facts for deltas) and reports budget_used + dropped_count; the injectable text field is rendered from the packed sets, so it honors the same budget the structured arrays report. It never trims client-side — you always know what was left out (dropped_count, and has_more on deltas). Pick a budget to fit the boundary: a session-start pack can afford more than a heartbeat delta.

Heartbeat cursor + dedup

Pass a stable session_id to delta and the brain keeps a per-session cursor: the first wake establishes it, each wake advances it. Dedup is cursor-based — a delivered page reappears only if it changes again after delivery (and then it should). Delivery is at-least-once: pages arrive oldest-first, and when a budget or the fetch limit drops some, the response sets has_more: true and the cursor advances only to the newest delivered page, so the tail surfaces on the next wake — nothing is silently lost. With no session_id you can still pass an explicit since for a stateless delta. The cursor is namespaced per caller ((source_id, client_id, session_id); authenticated remotes use their client id, auth-less remotes share a remote namespace, and local is reserved for the trusted CLI/hook lane), so a remote harness can never read or advance the local lane's cursor. Idle session cursors are garbage-collected after 7 days — a wake on an expired session re-establishes the cursor at now and returns an empty delta, so a harness returning from a long sleep should run one stateless since-based catch-up first.

Example — a cold session start (pull)

gbrain context-pack --entities "acme-example,alice-example" --budget-tokens 4000

Returns entity cards + open threads + hot facts, budget-packed, world-only. Inject the text field into the model's context before the first user message.