Push-based context (#2095, v0.42.43.0)
Retrieval used to be pull-only: the agent had to know to ask before the brain contributed anything. Push-based context inverts that — the brain volunteers relevant pages from the recent conversation, confidence-gated so push noise never becomes worse than pull silence. Three channels share one zero-LLM core (src/core/context/volunteer.ts):
How it decides
- Extract entities across the last N turns (capitalized runs,
@handles), merged with recency / frequency / user-role salience. Assistant-introduced entities and “what did she invest in?” follow-ups whose antecedent was named in the window now resolve. - Resolve through the alias table, exact titles, and slug suffixes — each arm carries an honest confidence: alias 0.9, exact title 0.8, slug-suffix 0.6, +0.05 when mentioned in ≥2 turns or the newest turn.
- Gate at
min_confidence(default 0.7 — slug-suffix matches need an explicit lower gate), suppress pages already surfaced (slug-presence only), cap at 3 pages (hard cap 5).
CLI
pages.last_retrieved_at > volunteered_at — the 5-minute last-retrieved throttle causes false negatives
and unrelated reads of the same page cause false positives. Use the per-arm
precision to tune min_confidence, not as an exact metric.
PGLite + modusbrain watch: PGLite is single-connection, and watch holds its
connection for the whole session — a concurrent modusbrain serve or any write
path blocks until watch exits. On a PGLite brain, run watch in bursts (piped
input exits at EOF) or use the ambient reflex channel instead, which routes
through a running serve’s resolve socket rather than taking the lock. Routing
watch through that same socket is a filed follow-up (TODOS.md). Postgres
brains are unaffected.
Config
Per-call knobs:
max_pages + min_confidence on both the op and modusbrain watch
(--max-pages / --min-confidence, plus --window-turns / --source on watch);
on the op only: prior_context (text whose already-surfaced slugs are suppressed),
session_id / turn attribution params (watch stamps its own per-session id and
turn numbers in the feedback log), and days to size the --stats window.
Storage + privacy
Volunteered pages log tocontext_volunteer_events (migration v117): slug,
arm, confidence, channel, optional session/turn — the rationale is a
deterministic template string, never raw conversation text. Event writes are
best-effort (fire-and-forget, drained at CLI exit) — the log is a tuning signal,
not an audit trail. Rows are pruned after 90 days by the dream cycle’s purge
phase. Synopses always strip the takes/facts fences — the same strip get_page
applies to untrusted callers, applied unconditionally here so private fence rows
never reach a prompt regardless of caller trust.