Demand-Driven Gateway Events
Context
The gateway extension drains Redis events by injecting them as user messages into the pi session, which forces an LLM response for every batch. Over 7 days this produced:
- 2,782 LLM responses, 1,335 from self-talk (responding to its own digest injections)
- ~157K output tokens mostly spent on “No operator action needed” and unsolicited strategic analysis
- 780 Telegram messages averaging 367 chars, many redundant triage summaries
- 269 automated digest injections, each triggering a full LLM turn
The AUTO_MESSAGE_DIGEST_ONLY_THRESHOLD = 20 only throttles which events pass through — it still injects messages that demand LLM responses. The gateway generates long strategic advice, personnel commentary, and play-by-play status updates that nobody asked for.
Decision
Switch the gateway from broadcast mode (inject events → force LLM response → route output) to demand-driven mode (accumulate context silently → surface when operator asks).
Rules
-
System events accumulate in a context buffer, not as user messages. The buffer is a structured summary stored in Redis and injected into the session via
before_agent_startas context — NOT as a user message that demands a response. -
Only critical events break through as proactive alerts:
- Sustained failures (pod down, worker crash, >3 consecutive errors)
- Security concerns (auth failures, secret expiry)
- Watchdog alarms (missed heartbeat — existing behavior, stays)
- Explicit operator-facing notifications with
critical: trueflag
-
When Joel sends a message, the accumulated context is prepended so the gateway knows what happened but only speaks about it if relevant to Joel’s question.
-
The gateway stops generating unsolicited triage/strategy. No “Three things worth your attention” unless asked. No personnel advice. No “No operator action needed.”
-
Subscription updates and feed digests go to the context buffer. They’re available if Joel asks “what happened” but don’t trigger responses.
-
Counter and digest-only mode are removed. The
automatedInjectedCount/AUTO_MESSAGE_DIGEST_ONLY_THRESHOLDmechanism is no longer needed — the default is silence.
Context Buffer Contract
interface GatewayContextBuffer {
events: Array<{
type: string;
summary: string; // one-line human-readable
ts: number;
critical: boolean;
}>;
lastFlushedAt: number;
eventCount: number; // total since last operator message
}- Stored in Redis key
joelclaw:gateway:context-buffer - TTL: 24h (auto-expires stale context)
- Max 50 events in buffer (oldest evicted)
- Flushed (cleared) after operator message is processed
Consequences
- Dramatically fewer LLM turns. Gateway only responds when Joel talks to it or when something is genuinely broken.
- No more Telegram spam. Proactive messages limited to critical alerts.
- Context is preserved, not lost. Events still accumulate — they’re just silent until relevant.
- Watchdog alarms unchanged. Missed heartbeats still fire immediately.
- Breaking change for gateway session. Requires daemon restart after deploy.