Designing Ambient AI Agents: Wake Funnels, Cheap Sleep and Safe Wakes
How to build event-driven AI agents that stay idle cheaply: layered triage before any model call, safe wake reconstruction, storm handling and attention budgets.
This article is published in English.
Sources: The Idle Agent: Designing Ambient, Event-Driven Systems That Wait Well
Most writing about AI agents starts at the moment a request lands and the loop begins to turn. An ambient agent, one that watches inboxes, queues and dashboards on its own, spends almost all of its life in the opposite state: nothing is happening, and the system has to decide, over and over, whether something just started to. This guide is about that idle time. By the end you will be able to design the layer that decides when an agent wakes, keep the cost of sleeping close to zero, make each wake safe against duplicates, staleness and injection, and measure whether the whole arrangement actually helps the people it interrupts.
A cautionary scenario: paying for every "no"
Picture a team that builds an agent to monitor its support inbox and its on-call channel. The goal is simple: flag anything that needs a person before any person has noticed it. The prototype is impressive in demos. Then the first monthly invoice arrives, and it is larger than the combined cost of the team's IDE licenses, CI minutes and observability tooling, for an agent that took roughly eleven useful actions in thirty days.
The reason is an architecture that nobody wrote down. To "watch" the inbox, a scheduled job ran every two minutes, gathered recent messages, and asked a frontier model whether any of it required attention. Over the month that happened about twenty-two thousand times. Almost every answer was a carefully reasoned "no". The eleven "yes" answers were excellent, but the invoice was dominated by the negatives. The single most expensive thing the system did, by around three orders of magnitude, was confirm that nothing had changed.
Elsewhere in the same infrastructure sat an ancient cron job that checked a disk threshold every minute. Over its lifetime it had cost essentially nothing. The difference is the lesson of this whole topic: waiting is something you design, not something that happens by default.
The idea to hold onto is this. An ambient agent is defined far more by what wakes it than by what it does once awake. The real engineering is a funnel that decides, as cheaply as possible, which of thousands of incoming events deserves the attention of a model, combined with a dormant state that costs nothing until one does. Chat agents never face this problem, because a person already judged the message worth sending before typing it. Remove that person from the trigger path and triage becomes your job. Solve it with the big model itself and you have effectively hired your most expensive specialist to sort the post.
This builds on a few ideas that deserve their own treatment: durable execution (a run that can park for days without consuming compute), temporal grounding (what an agent must relearn about "now" when it wakes), and goal drift in long-lived agents. They come up below where they matter.
Every prompt was already an event
A chat request looks like the natural starting point for an agent, but it hides a lot of free labor. The person who sent it did three things before any token was processed. They decided the situation was worth acting on, which is triage. They summarized it into a few sentences, which is context assembly. And they sent it at a particular moment, which is timing. A chat agent is really an agent sitting on top of an event layer powered by a human.
Ambient agents, a term LangChain popularized for agents that consume an event stream and respond to it, possibly handling several events at once, take that human out. All three free services disappear. What remains is an engineering problem with five distinct kinds of input, and each behaves differently:
- Messages. A person writes to the agent. These are rare, already filtered by human judgment, and full of intent. This is the easy case.
- Schedules. Cron and everything descended from it. A schedule fires whether or not anything happened. That is useful, because it catches what event streams miss, and wasteful, because most firings land in silence.
- Events. Webhooks, queue messages, new rows in a table. The outside world pushes them to you. They come in high volume, in bursts, with no triage at all, and they are authored by other systems and by strangers rather than by your user.
- Watches. Conditions over state: a pull request became mergeable, a document was edited, a customer stopped responding. Nothing pushes these to you. Something has to notice, and noticing has a price.
- Thresholds. A metric crossed a boundary. This is the oldest trigger in operations, and it comes with decades of hard-won alerting wisdom about fatigue, flapping and deadbands that agent builders are now rediscovering.
Designing an idle agent means deciding how these compose. Which of them can wake the agent? What sits between the raw signal and the model? What does the agent rebuild about the world when it wakes up? Err in one direction and you get the scenario above, a model reading silence every two minutes. Err in the other and the agent sleeps straight through the incident it exists to catch.
The wake funnel: triage as a staircase
The key economic fact is that a model call is the costliest conditional you will ever write. Asking a frontier model "does this matter?" costs something like five to seven orders of magnitude more than a database filter that answers the same question for structured data. So the working architecture is never a direct line from event to model. It is a funnel: a series of stages, each one cheaper than the next stage down, each one discarding most of what reaches it.
Stage one: structural rules
The first stage costs effectively nothing. It is plain code that inspects the shape of an event: its type, its sender, its labels, the repository or queue it came from. Newsletters, automated notifications, bot comments and events for projects the agent does not own can all be dropped here without any judgment at all. In a typical inbox, a large share of raw traffic never needs to go further. If fewer than half of your raw events are discarded at this stage, your rules are probably too timid.
Stage two: debounce and coalesce
Events arrive in bursts that share a single cause: dozens of emails in one thread, a push containing thirty commits, hundreds of alerts from one failing switch. The right unit for agent attention is not the individual event but the situation behind it. So this stage holds a short time window, groups incoming events by a correlation key such as thread, pull request or incident, and passes along a single combined signal for each situation.
Patience belongs in this stage too. A document that changed once is likely to change several more times in the next few minutes. If you wake on the trailing edge, a set interval after the most recent change rather than on the first one, you cut the number of wakes substantially and each wake sees a more complete picture. The same principle shows up whenever several writers touch shared state: a burst of forty events usually describes one fact.
A note on watches: poll and diff, never poll and judge
Watches carry a cost decision that the other triggers do not. Something has to notice the change, and there are exactly three ways to do it:
- The source pushes. A webhook or subscription tells you when state changes. When this exists, use it.
- You poll and diff. On a schedule, fetch the current state, compare it with the previous snapshot, and emit an event only when something differs.
- You poll and judge. On a schedule, fetch the state and ask a model about it. This is exactly what went wrong in the opening scenario.
Polling itself deserves a better reputation than that scenario suggests. Polling is cheap; judging is what is expensive. A scheduled job that fetches a page, hashes it and compares it with the previous hash costs a trivial amount per year. Plenty of systems offer no webhooks, so "never poll" is not a realistic rule. The real rule is that a poll must end in a diff, not in a model call. Take a snapshot, compare it, and let only a detected change enter the funnel as an event, where it faces the same rules and classifier as everything else. Whether something changed is a question for a hash function. Whether the change matters is the question you are reserving the model for.
Stage three: cheap classification
Whatever survives the rules and the coalescing goes to a small, fast, inexpensive model with a deliberately narrow prompt, something like "reply with one word: urgent, relevant or ignore." This is the familiar model-routing cascade applied to alerting: the cheap tier absorbs the ambiguity that fixed rules could not express, and only its "relevant" and "unsure" outcomes escalate. A small model that is right about 92% of the time, standing in front of a large model that costs thirty times as much, is the entire business case for this tier. For a broader look at where agent spend comes from, see an architecture-first cost model for agentic AI.
Stage four: the agent
Only at this point does the full harness start, with real context assembly, tools and a budget. In a healthy funnel only a sliver of the raw traffic ever gets this far, and every wake arrives already packaged as a situation rather than as a bare event.
Stage five: the human
The funnel continues past the agent, because the agent is also a filter: it chooses which of its findings are worth a person's time. That final stage is where ambient systems succeed or fail, and it gets its own section below.
The arithmetic of a redesign
Apply this to the team from the opening. Suppose they switch the inbox from polling to webhooks and add structural rules, which removes about 70% of raw events because they are newsletters and automated mail. Coalescing by thread removes roughly 60% of what is left. A small classifier then marks about 85% of the remainder as "ignore". The frontier model now runs roughly thirty times per month, down from twenty-two thousand, while the same eleven valuable actions still happen. The cost per useful wake drops by well over an order of magnitude.
The surprising part is that precision improves too. Each wake now looks at a coherent situation rather than whatever arbitrary slice happened to fall inside a two-minute window, so the model has better material to reason about.
Sleeping well: how an idle agent costs nothing
Between wakes, the ideal ambient agent does not exist at all. It is not running quietly in the background; there is no process, no container and no warm context. Its entire existence is a record in a store: an identity, a configuration, a pointer to its memory and a list of subscriptions. This is the durable-execution idea of "waiting is just state" taken to its logical end. A parked run is data at rest, and storing data at rest is one of the cheapest things a cloud provider sells.
That means waking up is an act of reconstruction. Everything that applies to resuming a paused workflow applies here with more force, because no one is watching when it happens.
Re-establish the clock
An agent waking after six days has to be told the current time and must recompute every relative reference it holds. A note saying "the deadline is Friday", written on a Tuesday, is simply wrong by the following Monday. Give the agent the current time in its principal's timezone, and the time of its last wake, so it knows how long it has been dormant.
Treat memory as possibly stale
The world kept moving while the agent was absent. Facts carried in memory should carry an as-of timestamp and be revalidated before use, and the wake context should favor fresh reads over remembered values. This is the same discipline you apply when a human approval step pauses a workflow: bind decisions to a snapshot, then revalidate when execution resumes.
Re-anchor on the goal
In long-running agents, the goal is effectively rebuilt from the context on every turn, which is why goals drift over weeks. A wake assembles its context from scratch, which makes it either the riskiest moment for drift or the best chance you will ever get to correct it. Done properly, every wake re-reads the goal definition. If an agent is rebuilt two hundred times a year, that is two hundred chances to pull it back onto its purpose at no extra cost.
This is why designs that start a fresh session per wake, keeping continuity in external memory and files instead of an ever-growing transcript, age much better than a single immortal session that accumulates months of residue. Scheduled-agent features in current coding tools, Claude Code's routines being one well-known example at the time of writing, largely follow this fresh-per-run model. That is a sensible choice for anyone who has seen what a context several weeks deep does to an agent's behavior.
What a good wake context contains
"Reconstruction" sounds abstract until you write one. A well-built wake prompt resembles a briefing that the harness puts together section by section:
- The goal file, unedited. The reason this agent exists and the limits on what it is allowed to do.
- The clock. The current time in the principal's timezone, plus the timestamp of the previous wake.
- The situation. The coalesced digest that earned this wake. Not forty raw events, but a description of their shape.
- Fresh state. Current values for everything the situation touches, fetched at wake time and each stamped with an as-of time.
- Relevant memory. A small set of durable notes left by earlier wakes, such as "this customer prefers evening calls" or "the last time this alert fired, the cause was the cache". These are retrieved as needed, not accumulated.
- The budget. Token limits, available tools and the autonomy ceiling for this particular wake.
Notice what is missing: the transcript of earlier wakes. Their conclusions survive, because each wake distills what it learned into memory before it ends, but the working residue of each session is discarded. That trade keeps the two-hundredth wake as sharp as the second. It also helps the bill, since a briefing of a few thousand tokens replaces a transcript that could run to hundreds of thousands.
Delivery guarantees, with an LLM twist
Waking also means inheriting the classic problems of distributed systems.
Delivery is at-least-once, so every wake has to be idempotent. Queues and webhook services all reserve the right to send you the same message twice. For a stateless notifier, a duplicate is just noise. For an agent holding tools, a duplicate can mean doing the same irreversible thing twice. The fix is the standard one: derive an idempotency key from the event and check it before the wake does anything that cannot be undone. If you need a refresher on the mechanics, see how idempotency keys work in Node.js POST endpoints.
Ambient agents also need a second, situation-level check. An agent woken because "PR #482 is mergeable" should confirm that the pull request is still mergeable before acting. The wake may be minutes old, and another actor, whether a person or a second agent, may already have dealt with it. Races at wake time are ordinary shared-state races with a longer delay between cause and effect.
Streams have holes, so every watch needs a periodic reconciliation pass. Endpoints suffer outages, subscriptions expire and providers sometimes drop deliveries without saying so. A watch built purely on reacting to events will eventually miss one without anyone noticing, and from the outside, an agent that is silent because nothing happened looks identical to an agent that is silent because it went blind. The fix is old and unglamorous: a slow scheduled sweep that compares actual state against what the event stream reported, much like the way payment systems reconcile what was intended, what was charged and what was delivered. Use push for latency and the sweep for truth.
Advanced concerns: adversaries, attention, concurrency and storms
The trigger is the attack surface
Revisit the five input types with a security mindset. Anyone who can send it an event can, in effect, prompt an ambient agent. Webhook payloads, email bodies and issue comments that are able to trigger a wake are all untrusted text, and they land in front of a model with tool access. Unlike chat, there is no person present at wake time to notice that something looks wrong. A carefully crafted "urgent" email does more than waste a wake; it decides what the agent thinks about, and that is the opening move of nearly every prompt-injection chain.
The standard mitigations all apply. Treat event content strictly as data. Sandbox the ambient agent more tightly than you would a chat agent. Keep apart the three dangerous capabilities of private data access, exposure to untrusted content and the ability to communicate externally; an inbox-watching agent with broad tools and outbound messaging has all three and a doorbell. Add one rule specific to ambient systems: autonomy should scale with how much you trust the trigger. A wake caused by your own schedule may act. A wake caused by content from an outsider should mostly notify.
The human is the scarcest resource in the loop
Most of what an ambient agent produces is interruptions of people, and interruptions are a currency that loses value when overissued. A useful pattern, described well by LangChain's agent inbox work, is a three-step ladder for what a wake may ask of a person:
- Notify. For information only; no action is needed.
- Question. The agent needs a single fact before it can continue.
- Review. The agent has prepared an action and wants approval.
The ambient-specific insight is that this ladder doubles as your quality metric. Record how people respond to each interruption: acted on, dismissed or ignored. That gives you a precision measurement for the entire funnel. An agent whose notifications are ignored 80% of the time is not merely 80% wasted. It is training people to mute it, and once they do, the useful 20% disappears as well. Alert fatigue undermined monitoring rollouts for decades before language models existed, and eloquent alert text does nothing to change that.
Concurrency: a superpower with a hazard attached
The definition of an ambient agent includes acting on several events at once, and that detail is easy to miss. A chat agent handles one conversation. An ambient agent could have forty wakes in flight at once, every one in a separate clean context, every one holding a partial view of shared reality. You have acquired a multi-agent system without deciding to, along with its shared-state problems. Two wakes caused by related events might grab the same ticket, write conflicting answers in one thread or both take the same task, and neither can tell, since clean contexts share nothing with each other.
The mitigations, in rough order of preference:
- Partition wakes by correlation key so that each situation owns its state. The grouping you built in stage two works as an ownership rule as well: each situation gets exactly one wake and no parallel twin.
- Route writes through a single writer where partitioning is not enough.
- Use optimistic concurrency where two wakes truly must touch the same object, and treat a conflict as an error, so the second writer re-evaluates its decision instead of overwriting the first.
If the funnel is built well, most of this comes for free, and that is no accident. The correlation keys that group events and the ownership keys that protect state naturally want to be the same keys.
Storm mode
A single upstream incident can emit ten thousand correlated events. A naive funnel turns those into ten thousand wakes, a sharp spike in token spend and forty notifications that get the channel muted in the middle of the incident. Operations teams solved a version of this long ago with flap detection and incident grouping.
The agent equivalent is a storm detector that compares the current event rate against a baseline and, when it spikes, switches the funnel into a different mode. In storm mode, everything correlated is folded into one situation, a single agent is woken with the digest, and it receives a specific brief: this is a storm; summarize it, identify the most likely common cause and send one notification. The cost control matters, since the tail of your workload is where budgets get destroyed, but the attention argument matters more. During an incident, a person's capacity to absorb interruptions falls at exactly the moment the event rate climbs. Storm mode is the funnel respecting that inversion.
Measure the idle agent like a product
Two numbers matter most:
- Cost per useful wake. Total spend divided by the number of wakes that a person, in hindsight, agrees were worthwhile. This is unit economics applied to your own system.
- Triage precision and recall. These can be evaluated offline very effectively. Feed thirty days of past events through a candidate funnel and compare the wakes it would have triggered with how people really responded.
That replay suite is one of the rare evaluations that is nearly free to build, because the labels already exist in your ticket history. It turns changes to the funnel from matters of opinion into measurable differences.
Autonomy that depends on the clock
One more pattern is cheap to implement and oddly rare: let the autonomy ceiling of a wake depend on when it fires and who can be reached. A finding that justifies an automatic fix at 11 a.m. on a Tuesday, with people online, a stop button close at hand and the blast radius well understood, might deserve nothing more than an alert in the early hours of a Sunday.
This is not excessive caution. It is an expected-value decision with time as an input. The cost of asking is low during working hours and very high at night. At the same time, the benefit of human oversight, the probability that someone catches a mistake multiplied by the cost of that mistake, shrinks at night because nobody is watching. So the error term dominates and the threshold should move toward asking, which in practice means deferring, since there is no one awake to answer.
Encode this as a lookup in the harness that combines trigger trust, action severity and human availability, and maps them to one of three outcomes: act now, queue for the morning or notify immediately. The queue-for-morning option is the unsung hero. Most things an ambient agent notices at 3 a.m. are perfectly fine as a review item waiting at 8:55 a.m., already packaged with the agent's proposed action, arriving about when the first coffee does.
Patterns in real systems
An email assistant with an inbox for its humans
LangChain's reference ambient agent handles email: it drafts replies, files messages and escalates. Its interaction design is more instructive than its drafting. The team behind it frames human-in-the-loop not as a concession but as something that lowers the stakes and makes shipping easier, builds trust and feeds long-term memory. Their Agent Inbox, a single reviewable surface listing every open thread between a person and their agents, is the notify, question and review ladder given a physical form. A running joke from that project, that if you were ignored it was surely the agent's fault, captures the whole attention economy: the agent exists to spend a person's attention more wisely, and the jokes begin when it does not.
Scheduled agents in coding tools
Major coding-agent platforms have been adding agents that run on schedules and repository events instead of prompts; Claude Code's routines and GitHub-triggered runs are examples many developers will have encountered. Check the current documentation, because these features are evolving quickly. Two design choices recur across them, and both support the argument here. Every run starts a fresh session, with continuity carried in files and memory rather than an endless transcript. And the trigger layer is classical infrastructure, such as cron expressions, webhook filters and conditional YAML, with no model anywhere in the triage path. The intelligence is expensive and the alarm clock is cheap, so the products keep them separate.
Infrastructure watchers
Cloud providers have described patterns for ambient agents that monitor infrastructure and raise findings proactively. The well-designed ones look like this guide put into practice. Events come from the platform's native event bus, so structural filtering is available for free. Events are correlated before any agent is invoked. And for anything consequential, the agents produce findings for review rather than applying fixes on their own. The detail worth borrowing is the trust gradient: the further a proposed action reaches, the higher up the notify, question and review ladder it goes. Watching can be autonomous; touching is supervised.
The polling team, one quarter later
Return to the team from the opening after the redesign has settled. Their funnel now consists of webhooks, thread coalescing with a ten-minute quiet period, a small classifier whose entire prompt would fit on an index card, and around thirty frontier-model wakes per month. Two results stand out. The cost per useful wake falls by roughly forty times. And, unexpectedly, the catch rate rises. The polling design had been cutting situations into arbitrary two-minute slices, and on at least two occasions it dismissed a partial view of something that, taken as a whole, clearly deserved a "yes".
So the redesign did more than cut costs. Grouping events improved the quality of the judgments, since the model was finally evaluating whole situations instead of arbitrary fragments of them. The scheduled job was never the problem; asking a model to judge every tick of it was.
Choosing your building blocks
Most of this stack should be bought or reused rather than built.
- Trigger infrastructure. Cron and its managed equivalents; event buses and queues such as EventBridge, Pub/Sub, Kafka or plain webhooks; and schedules and signals in workflow engines such as Temporal, Restate or Inngest, which also give you durable parking. Stages one and two of the funnel map directly onto what these tools already do.
- Ambient-agent scaffolding. LangGraph, with persistence, interrupts and cron support, plus the open-source Agent Inbox; the scheduled and triggered modes of major coding agents, such as Claude Code routines and GitHub Actions integrations; and a growing set of connectors that turn email or webhooks into agent runs. Judge all of them on three questions: where triage happens (it should be before the model), what a wake reconstructs, and what the person ultimately sees.
- Triage tier. Any small, fast model will do. The discipline lies in the narrow prompt and the offline replay evaluation, not in which model you choose.
- The inbox. Use LangChain's Agent Inbox if you want an existing surface, or your team's current channels such as Slack, email or tickets, with the three verbs kept explicit and measured.
Spend your novelty budget on the funnel and on wake-context reconstruction, and buy everything else. Schedulers are a solved problem with decades of battle testing behind them. A homemade loop that polls a model every two minutes is not.
The whole design fits in a few lines of pseudocode. Read it top to bottom as the funnel: a free rule check, coalescing into a situation (returning nothing while a burst is still settling), cheap classification, an idempotency guard against duplicate delivery, reconstruction of the wake context from the current time, the goal file and fresh reads, a budgeted agent run, and finally delivery through one of the three inbox verbs.
async def on_event(evt):
if not rules_pass(evt): return # stage 1: free
sit = coalesce(evt, window="10m") # stage 2: situations, not events
if sit is None: return # burst still settling
if triage_small_model(sit) == "ignore": return # stage 3: cheap
if seen(sit.idempotency_key): return # at-least-once armor
ctx = rebuild(now(), goal_file, fresh_reads(sit)) # stage 4: wake = reconstruction
outcome = await agent.run(sit, ctx, budget=WAKE_BUDGET)
inbox.deliver(outcome.verb, outcome.summary) # notify | question | review
Note where the idempotency check sits: after the cheap filters but before anything expensive or irreversible. It could equally sit earlier; what matters is that no duplicate ever reaches agent.run. In a real system, rebuild is also where the situation-level check-before-act belongs, since it is the first moment fresh state is available.
A field guide to failure modes
- The polling bonfire. An expensive model is repeatedly asked to inspect nothing. Cure: rules and coalescing ahead of any model call, then a cheap model ahead of the expensive one.
- The thundering herd. A single outage fans out into thousands of wakes. Cure: storm mode, with a rate detector, full coalescing, one agent and one notification.
- The double wake. A redelivered event reaches an agent that can take real actions. Cure: idempotency keys on wakes and a check-before-act on the situation.
- The stale wake. Decisions rest on a snapshot from the moment the trigger fired, even though reality has since moved on. Cure: every wake re-reads the time, fetches fresh state and revalidates facts before taking any action.
- The injected wake. Content from an outsider decides what your autonomous agent pays attention to. Cure: treat event content as data, scale autonomy with trigger trust, and sandbox ambient agents more strictly than chat agents.
- The muted inbox. Interruption precision decays until people stop listening. Cure: track acted, dismissed and ignored for every notification, and treat an acted-on rate below 50% as an outage.
- The silent gap. A webhook stopped delivering months ago and nobody noticed until a renewal was missed. Cure: push for latency, sweep for truth, with a slow reconciliation job that assumes the stream is lying.
- The immortal daemon. One session stays alive for months and slowly drifts from its goal. Cure: a fresh session per wake, with continuity kept in files and memory rather than a transcript.
- The midnight surprise. The most dangerous action runs in the middle of the night because no one was available to object. Cure: route consequential actions through review, make autonomy thresholds depend on the hour, and keep a working cancel switch close at hand.
A one-week plan to get started
- Audit your triggers. Write down every path that can start your agent today and what each firing costs. Mark any path that amounts to "call a model on a timer" as the first thing to fix.
- Build stage one. Put structural filters in front of every trigger and measure the discard rate. If it is below half, your rules are too cautious.
- Coalesce. Choose correlation keys such as thread, pull request, incident or customer, add a trailing-edge debounce, and change your agent's input from "an event" to "a situation".
- Add the triage tier. Use a small model with a one-word output. Then build a replay evaluation from last month's events and the responses people actually gave, and score the funnel's precision and recall before you rely on it.
- Make wakes safe. Add idempotency keys, check-before-act, and the reconstruction routine: clock, fresh reads, goal file.
- Install the ladder. Make notify, question and review explicit output types, delivered somewhere you can track, and start recording whether each was acted on, dismissed or ignored.
- Run two drills. Replay a burst to confirm that storm mode coalesces it, and disable a webhook for an hour to confirm the sweep detects the gap. Finally, calculate cost per useful wake for the first time and display it next to token spend.
Wrapping up: ambient perception, human commitment
There is a real debate about where agent interfaces are heading. One side argues that chat is a transitional interface and that agents will increasingly live inside event streams, noticing problems before people do. Attention is the scarcest thing knowledge workers have, and software that spends its own attention on watching, and spends yours only when it is warranted, is simply better software.
The other side points out that an always-on agent with tools combines exactly the risks discussed above: untrusted triggers, no person present at wake time and autonomy in the middle of the night. From that view, the prompt was never overhead. It was consent, and every step that removes a person from the loop shifts risk from the moment of action onto the quality of your guardrails.
Both sides have a point, and the funnel is where they meet. Watching everything is achievable, but notice that what made the examples above succeed was traditional engineering: filtering, debouncing, idempotent handling, reconciliation jobs and care about alert fatigue. Commitment still needs consent, which is exactly what the notify, question and review ladder expresses: autonomy for noticing, escalation for acting. The recipe is agents that observe broadly, wake seldom and seek approval before changing anything that matters.
A useful exercise takes one evening. Choose the loudest stream of notifications in your own working day and outline a funnel for it: what a simple rule could drop, what would coalesce, what a small model could triage and what would genuinely deserve a wake. You will have designed your first idle agent before writing any of its code.