Proactive by Construction: Why the Next Generation of Agents Must Anticipate, Not Just React A developer outlines a "Proactive by Construction" architecture for AI agents that continuously monitor state, forecast needs, and act before users ask, rather than waiting for each message. The design combines persistent domain state and provenance graphs, explained-information caches, offline-capable UI agents, smart session and sync protocols, a layered sandbox/classifier/LLM security and cost hierarchy, and a simulation and risk engine to anticipate critical thresholds. The author argues this state-driven approach cuts long-run LLM costs and latency compared with reactive, event-driven agents that spend expensive model calls on every inbound event. Executive Summary: Current AI assistants are mostly reactive : they wait for a user’s message, run the model, and answer. This works for simple queries but wastes the many idle cycles between interactions. In contrast, a truly proactive agent continuously monitors state, predicts future needs, and acts or prompts the user before being asked. Here we argue that instead of bolting on occasional webhooks or notifications, the entire architecture should be designed for proactivity . This “Proactive by Construction” approach minimizes wasted user-initiated messages and shifts heavy work into idle periods. We compare the reactive, event-driven architecture e.g. waking on every email with a state-driven proactive design. We detail how to build the latter using 1 persistent domain state and provenance graphs, 2 explained-information caches, 3 offline-capable UI agents, 4 smart session and sync protocols, 5 a layered security/cost hierarchy sandbox + cheap classifier + full LLM , and 6 a simulation/risk engine to anticipate critical thresholds. For each, we outline benefits reduced cost, faster responses, user trust , costs engineering complexity, storage , security considerations, and implementation notes. We include comparative tables and diagrams mermaid of architectures and data flows. All designs are assumed unconstrained no fixed cloud infra or model limits and prioritize user utility over technical gimmicks. “Proactive First” Product Blurb: “Our assistant doesn’t just wait; it stays one step ahead. It monitors your business data, forecasts potential issues, and prepares answers or alerts before you even ask. User prompts become confirmations rather than requests. Proactive First means the system uses idle time on the highest-value tasks so that when you do ask something, the answer is already there.” Most deployed agents today follow a chatbot model. They sleep until a user message arrives, then fetch data, call the LLM, and reply. This is simple, but it creates high latency each turn costs many tokens and misses the chance to use downtime productively . In contrast, a proactive agent treats idle time as an opportunity to prepare. Instead of user→agent→response , it continuously evaluates the business state, forecasts, and incoming events, and decides when and if to speak up. | Property | Reactive/Event-Driven | State-Driven/Proactive | |---|---|---| | Cost | High per event LLM cost on every webhook . | Lower long-run cost: expensive LLM calls only when needed, plus lightweight tracking. Enables batching work in idle moments. | | Latency | High at query time full LLM run . | Faster responses when asked answer often precomputed . | | User Effort | High must trigger each query . | Low: fewer manual queries, more automatic summaries/alerts. | | Privacy | Many messages/queries over network. | Local processing and caching means less raw data sent out. | | Complexity | Simpler design, but fragile at scale cost/security issues . | Higher system complexity state management, sync, simulations but much richer behavior. | | Proactivity | None – only reacts. | Full: anticipates tasks, can initiate actions or ask clarifying questions. | In short, reactive agents expend expensive LLM calls on all inbound events 95% of which are noise . State-driven agents, by contrast, filter and summarize locally, predict what’s needed, and only then prompt the LLM or user. This division of labor cheap local vs. occasional expensive reasoning yields huge savings and faster turnarounds. Below is a high-level architecture of our proactive agent system. It contrasts with a simple “agent-as-backend” model. Here, the UI-local agent and background agents handle much logic client-side and sync to the backend only deltas events or requests . The backend remains the authority on domain state and data. flowchart LR subgraph Frontend WA WhatsApp/Mobile Chat Web Web GUI / Desktop App WA -- Message→ AgentUI UI-Local Agent Web -- Action→ AgentUI end subgraph Mobile/Shop LocalDevice Local Device AgentUI -. offline .- LocalDB Local Store end subgraph Backend BackendSystem Core Backend\nDomain State & DB ProvenanceDB Explained Data & Provenance end UserSentinel UserSentinelAgent -- heartbeats → AgentUI AgentUI -- delta/sync → BackendSystem BackendSystem -- ProvenanceDB AgentUI <-- LocalDB The UI-local agent in browser or app maintains session state, local cache, and offline interaction. It communicates with and is supervised by a UserSentinelAgent via periodic SessionACKs heartbeats . Only when something meaningful occurs or periodically does it sync updates to the BackendSystem , which persists authoritative state and explanations. The backend can update the UI only by responding to these syncs front-end initiated sync model , not by continuously pushing. A core design is to separate authentication/presence from interaction preference . Each user session has: Concretely, the UI agent sends a SessionACK a simple heartbeat including last activity to UserSentinelAgent on the backend every minute. The sentinel checks how long since last real user reply. If near timeout, it triggers the “continue session?” prompt. If timeouts fully, it closes the session. This keeps both sides in sync: the frontend initiates syncs sending events/deltas to backend , rather than backend continuously polling clients. The UI agent can continue operating offline answering questions from local cache and simply queues a delta to send later. Benefits: Reliable session control, user stays in control of inactivity. Separating idle presence from authentication avoids spamming the user they can go “quiet but logged in” . Costs: Slight added complexity in managing heartbeat logic and session flags. Security: This avoids stale credentials or orphan actions – every critical action is re-checked on the backend. Implementation: Store a last-ACK timestamp per session in backend. On each frontend interaction reset it. Sentinel runs a timer to expire sessions if no ACK. Central to proactivity is the notion of self-explaining state . Every important derived Information e.g. “Forecast for next month: $18,450” is stored along with its provenance : exactly what raw values and operations produced it. We structure this as a graph of value identities . For example: { "information context": "sales.forecast", "information id": "2026-10-04", "value": { "forecast": 18450 }, "provenance": { "values": { "777": { "value": 142.50, "source": "sales.123", "field": "total", "version": "2026-09-30T12:00:00Z" }, "1432": { "value": 89.90, "source": "sales.124", "field": "total", "version": "2026-09-30T12:05:00Z" }, "111": { "value": 37, "source": "stock.981", "field": "available", "version": "2026-10-01T08:00:00Z" }, "4": { "value": "pharmacy", "source": "customer segment.42", "field": "type", "version": "2026-08-15T00:00:00Z" } }, "operations": { "operation": "aggregate", "inputs": 777, 1432 }, { "operation": "join", "inputs": 777, 111 }, { "operation": "forecast", "inputs": 9001, 111, 4 , "model": "ARIMA-v2" } }, "explanation": { "pt-BR": "Explicação detalhada em português...", "audio": " link to pre-rendered audio ", "short": "Resumo breve...", "detailed": "Explicação completa detalhada..." } } In this scheme, each raw or intermediate value has a unique ID e.g. 777 , 1432 . From the ID we know exactly which source record and field it came from and even the timestamp/version of that record . The provenance graph traces how each value fed into operations to produce others see Mermaid example below . This lets the agent reconstruct, deterministically, how any information was computed, without re-running the raw data queries. flowchart LR subgraph Provenance A "sales.123.total = 142.50 v2026-09-30 " B "sales.124.total = 89.90 v2026-09-30 " C "stock.981.available = 37 v2026-10-01 " D "customer segment.42.type = \"pharmacy\" v2026-08 " E "aggregate 142.50, 89.90 = 232.40 id 9001 " F "join 232.40, 37 = 269.40 id 9002 " G "forecast 269.40, 'pharmacy' = 18450" end A -- E B -- E E -- F C -- F F -- G D -- G Benefits: The system always knows where each piece of information came from. When the user asks “Why is the forecast $18,450?” we don’t blind-call an LLM on the raw database. Instead we feed the above structured provenance into a context prompt to generate a natural-language explanation. This ensures explanations match the true data lineage. We also generate different forms “short” vs “detailed”, audio, localized languages up front and store them. Costs: Storing the provenance graph increases storage especially if values/versions are stored . Querying it on the fly needs careful indexing. But these are standard issues with event-sourced or knowledge-graph databases. We offset cost by reducing repeated LLM calls and by compressing provenance in JSONB blobs see below . Security: The provenance data are derived from business data, so they carry no secret beyond what the user is authorized to see. The main risk is that an LLM might hallucinate explanations beyond the given facts; by bounding the LLM context to the provenance and using a deterministic “explain” prompt, we prevent falsification of the chain. One can include provenance hashes to verify no tampering of stored graphs. Implementation: Use a hybrid relational/JSONB store. Key tables hold stable entity state and base events, while a JSONB column holds each Information’s provenance and explanations. Include a provenance hash e.g. SHA256 of the sorted provenance entries to detect if the underlying data changed; if so, invalidate the cached explanation. Queries by information context and information id retrieve value and provenance quickly index these fields . Once an explanation is generated for a given information e.g. a forecast or anomaly alert , we cache it . That is, for each information id, version, locale, detail level we store the text and audio explanation. Next time anyone asks the same question, or a semantically equivalent one, we can replay the cached response. In practice: hash is identical and context unchanged do we reuse the old explanation. Otherwise we prompt the LLM anew and update the cache. This avoids stale explanations and unnecessary LLM calls. Benefits: Dramatically lowers LLM usage. Once explained, answers are instant. It also ensures consistency in replies. Costs: Extra storage but text is cheap . Slight complexity in cache invalidation logic. Security: No new issue – the cache just reduces recomputation. Notes: This is akin to “explainable materialized views” in a database, a technique known from data lineage research. We strongly advocate an offline-first UI agent design. The UI browser app or shop terminal stores all viewed data locally , so the user’s context and requested reports are instantly available even without network. For example, when a shop employee requests a sales report, the UI fetches it once and keeps it. If they ask follow-up questions “What contributed to the trend?” , the agent can answer from its local cache of values and explanations. This is facilitated by: Thus each client phone/web becomes its own mini-agent: it can answer many questions from its cache including anything explained previously , prompt the user to re-authenticate if needed, and even simulate risk scenarios locally. We can even ship small “sleeping” agents on devices that wake on schedule and process data. Benefits: The assistant feels immediate no lag waiting on network for each query . It also scales effortlessly: users' requests don’t hit the central backend unless needed. Costs: More complexity in client code and data sync logic. Must handle conflict resolution resolve if same data updated in parallel clients – use last-write-wins or merge strategies . Security: Local data must be encrypted or sandboxed, as it may include sensitive info. Implementation: Use proven PWA/local-first frameworks service workers, IndexedDB, CRDT libraries . Key references: “Offline-first frontends make the app part of a distributed system”. To bridge front-end autonomy with centralized control, we introduce a session heartbeat pattern. The UI agent and WhatsApp bot periodically send a minimal SessionACK message to the UserSentinelAgent on the backend. This message might include the user ID, channel WhatsApp/Web , last action ID, and a timestamp. The sentinel uses this to: On the backend, UserSentinelAgent simply updates the session’s last-active timestamp. It does not query the frontend; it passively waits for ACKs. If an ACK is overdue, it starts session termination. Conversely, the front-end never blocks waiting for the backend on every event – it locally updates state and asynchronously sends a short “what happened” notice later just the essential event IDs or state changes . Benefits: Ultra-lightweight server. Avoids polling. Maintains security no user action happens without backend confirmation . Costs: Requires the backend to trust the sequence of ACKs they should be signed or validated . Security: We guard against replay attacks by including a monotonically increasing counter or nonce in each ACK. If an attacker tries to spoof an ACK, it will have an invalid sequence number or be rejected by the sentinel. Inspired by uriwa’s Reddit proposal , we use a three-tier pipeline for external events emails, webhooks, sensor streams : Sandboxed Edge Code pre-filter : Incoming events e.g. email text, chat mentions are first processed by a tightly sandboxed script no loops, no arbitrary code execution . This extracts key fields and calls a decision model a small inference engine . Because it’s sandboxed, even if an attacker injects malicious content, it cannot execute on our server or leak secrets. Decision Model System 1 : This is a compact classifier e.g. a small transformer or tuned model that answers yes/no or scores "Should I wake the agent?". For example, “Does this email need our attention?”. Unlike a generative model, it emits a bounded label, and runs in milliseconds at a fraction of the cost ∼1/100th . This filters out ~95% of noise for near-zero cost. Full Agent Loop System 2 : Only if the decision model says “yes” do we notify the agent . Critically, rather than blasting the user with a cold message, we inject a structured notification into the existing conversation thread. The agent then wakes with full context persona, history, tools and can formulate a proposal. E.g. “I drafted a reply…” The user confirms, and the agent acts. This layered approach means: cheap code handles routine parsing, a tiny AI filters events, and the big LLM only runs for real tasks. It solves the “cost trap” and “security trap” noted on Reddit where arbitrary webhooks would otherwise spam or expose the system . Benefits: Orders-of-magnitude cost reduction. Better security: sandboxing prevents prompt injection from executing sensitive actions. Users only get contacted for true positive events. Costs: Building and maintaining the decision model; ensuring it stays high-precision missed events = lost opportunity . We mitigate that by continuous learning feedback from user: “no action needed” vs “good alert” . Implementation: Use a policy engine like OpenAI’s new classification APIs or a small distilled model. Run it in a WASM or custom sandbox. The decision model’s queries are few-token prompts “Is this email urgent?” to minimize token use. To be truly proactive, the agent not only reports current stats but also simulates future scenarios using cached data. For example, given past sales trends and current inventory, the agent can probe “What if sales slow by 10%?” or “What if supply is delayed 5 days?” and see how KPIs would change. In practice, we: This is essentially building a what-if engine on cached data. Because it uses historical and current numbers already in the database, the agent can run these probes offline or cheaply on a separate process and surface the results as pre-generated reports or alerts. The user’s questions become more exploratory “show me the high and low scenarios” rather than constructive. Benefits: Dramatically shifts the assistant from passive to preventive . Users get warned in advance of problems and informed of solutions. Costs: Increased computation for simulations likely done during low-load periods . More complex logic to define risk bands and actions. Security: Fully on-user’s data, no extra risk. Notes: This aligns with research in proactive health/finance systems that run “Monte Carlo scenario analysis” on the side. Here the outputs tables or charts can be cached in the ExplainedInformation store with provenance. In the UI, an agent-like component listens to the user’s free-form queries in chat or voice and handles them as follows: ExplainedInformation and its provenance, and returns the answer possibly filling in variables . The LLM is Only if the intent remains ambiguous do we defer to the full System-2 loop. This multi-layered local reasoning regex → semantic classifier → LLM mirrors the Reddit pattern: cheap checks first, costly calls last. Benefits: Very low-latency responses for common queries. Drastically fewer LLM calls. Costs: Building and curating intent templates; training light classifiers. Security: Local matching never leaks data. Implementation: Store a mapping of intent keywords → information IDs in the frontend. Use regex to catch obvious questions. Keep an on-device mini LLM or API for semantic matching if needed. Practically, we store explained information and provenance in a relational DB with JSONB fields. For example: information information id PK, context, timestamp, value JSONB, provenance JSONB . explanations info id FK, version, locale, audience, explanation JSONB, provenance hash . context, timestamp and on provenance hash since many queries will check for changed data . This hybrid model retains the query efficiency of SQL e.g. find all info for given date range while storing flexible, nested provenance and explanation data in JSONB which PostgreSQL can index on keys . Benefits: Flexible schema we can evolve provenance shape without migrating whole tables . Powerful JSONB indexing allows quick lookup by info ID or by provenance attributes if needed. Costs: More complexity in schema design. JSONB queries can be slower than pure SQL, but most reads are by key. Security: Standard DB security applies; ensure JSON content is validated on insert. 1. Reactive vs. State-Driven Proactive | Dimension | Reactive Webhook | State-Driven Our Design | |---|---|---| | Cost | High API & LLM cost invoke on every event . | Low – cheap filtering + batched processing. LLM calls only for true alerts. | | Latency | Slow per request full prompt, tool loop . | Fast answers for precomputed info. Interactive queries often answered locally. | | Privacy | Many messages to cloud, more exposure. | Mostly local. Only deltas and flagged events sent to backend. | | Complexity | Simple design, but scales poorly cost, security issues . | More components cache, probes, sync , but efficient and robust. | | Proactivity | None user must ask for updates . | Full anticipates needs, alerts proactively . | | Trust & UX | Users often spam queries if they don’t see updates. | Users trust agent to speak up only when needed. | 2. Component Responsibilities & Data Flow | Component | Responsibility | Data Flow | |---|---|---| | WhatsApp/Mobile | User interaction via chat/voice. | Sends user inputs to UI agent; receives text/audio reply. | | Web UI / Desktop | Visual interface, optional mic/voice for shops. | Sends clicks/voice to UI agent; displays charts, prompts. | | UI-Local Agent | Client-side agent harness. Manages session, cache, local Q&A, and UI updates. | Reads/writes LocalDB; sends SessionACK & deltas to BackendSystem; receives updated state or explanations. | | LocalDB | On-device storage of user’s data cache of info & provenance . | Queried by UI agent for fast local answers; syncs with Backend. | | UserSentinelAgent | Backend presence monitor. Handles timeouts and session control. | Receives SessionACK pings; triggers session renewal prompts or logout. | | BackendSystem | Authoritative domain logic and data. Applies events, updates state. | Receives deltas/requests from UI; emits updates and notifications back. | | ExplainedData Store | Database of all explained information, provenance, cached explanations. | Queried by backend and UI for any needed info. Updated when new info created. | | Sandbox Layer | Optional edge service Runs untrusted code or parsing safely. | Processes external webhooks emails etc. before passing to agent. | | Decision Model Edge | Fast classifier filtering events. | Takes parsed event info; returns “wake” boolean. | | Agent Loop | Full LLM reasoning when needed chat loop, tools . | Operates on user-turn or triggered notifications. | | Simulation Engine | Offline scheduler for what-if analysis. | Reads historical data; writes predicted metrics/alerts to Backend. | In summary, Proactive by Construction demands that we stop treating proactivity as an optional “plugin” and instead embed it in every layer: from state storage to UI to decision policies. By doing so, the agent learns to use downtime , minimize manual queries , and explain its knowledge , ultimately delivering a smarter, faster, and more trustworthy assistant.