Polling Agents in AI Assistants: 11 Implementation Patterns A new guide outlines 11 implementation patterns for polling agents in AI assistants, enabling proactive background monitoring of sources like inboxes, task lists, and GitHub issues. The patterns emphasize using deterministic infrastructure for time and state management while reserving language models for semantic interpretation. This approach transforms AI assistants from reactive chatbots into proactive background processes that act on users' behalf. Polling Agents in AI Assistants: 11 Implementation Patterns Reliable polling patterns for AI agents. Polling agents are one of the least glamorous parts of AI assistant architecture, but they are also one of the most useful. A normal chat assistant waits for the user to ask something. A polling agent keeps watching. It checks a source, notices changes, decides whether anything matters, and then acts. That action may be a notification, a summary, a draft, a tool call, or a full workflow. This is how an assistant moves from “answer my question” to “keep an eye on this for me.” Instead of being reactive, it becomes a background process that notices things on the user’s behalf and acts when conditions are met. The important design point is simple: do not make the language model responsible for time, state, retries, or locking. Use normal backend infrastructure for that. Use the model where it is valuable: interpreting messy context, making semantic judgments, and producing useful language. What Is a Polling Agent? A polling agent is a background process that repeatedly checks a source and triggers an assistant action when a condition is met. In the broader AI Systems https://www.glukhov.org/ai-systems/ stack — where the assistant combines an LLM, memory, tooling, routing, and observability — the polling layer is what makes the assistant proactive rather than purely reactive. For the full five-layer picture, see AI Assistant Architecture: LLM, Memory, Tools, Routing, Observability https://www.glukhov.org/ai-systems/architecture/ai-assistant-architecture/ . Examples: - Check an inbox every morning and summarize important messages. - Watch a Notion task list and execute the next todo item. - Monitor a GitHub issue until it changes status. - Poll a long-running AI job until the result is ready. - Check a booking slot until one becomes available. - Watch a supplier portal until a document appears. - Scan new research papers once per week and summarize relevant ones. A practical polling agent has five responsibilities: - Wake up at the right time. - Read from the source. - Remember what it has already seen. - Decide whether the new state matters. - Act once, safely, without repeating itself. A typical production flow looks like this: php scheduler - polling worker - source system - state store - deterministic filters - optional LLM evaluation - assistant action This structure is boring in the best possible way. Boring systems are easier to debug at 2 AM. The State Every Polling Agent Needs Polling agents need durable state. Conversation history is not enough. The assistant may remember the conversation, but the system needs a reliable operational record. A good polling state record usually contains: { "poll id": "poll 123", "user id": "user 456", "source type": "notion", "source ref": "database tasks", "condition": "take one task in Todo state and execute it", "interval seconds": 600, "last run at": "2026-06-19T01:00:00Z", "next run at": "2026-06-19T01:10:00Z", "last seen cursor": "cursor or timestamp", "last result hash": "b64e8a...", "failure count": 0, "status": "active" } The exact schema depends on the source, but most systems need these concepts. Poll Definition This describes what the agent is watching and why. poll id user id workspace id source type source ref condition text priority status For example: source type: notion source ref: Tasks database condition text: Find one Todo task, claim it, execute it, mark it Complete. Schedule This describes when the agent should run. interval seconds cron expression timezone last run at next run at jitter For a Hermes agent that checks Notion every 10 minutes: interval seconds: 600 timezone: Australia/Melbourne Cursor or Snapshot This helps the agent avoid reprocessing the same data. Depending on the source, this may be: last seen id last seen timestamp api cursor etag version content hash For a Notion task queue, the cursor may be less important than task status and claim fields. For Gmail, GitHub, or a sync API, the cursor is usually critical. Claim or Lease This prevents two workers from taking the same job. claimed by claimed at claim expires at run id For example, a Notion task can be changed from: Status: Todo to: Status: InProgress ClaimedBy: hermes ClaimedAt: 2026-06-19T01:00:00Z ClaimExpiresAt: 2026-06-19T01:30:00Z RunId: run 789 This is the difference between “I hope only one worker picks it” and “the system has a claim protocol.” Execution Record This records what happened during a run. run id poll id source object id started at finished at status items checked items changed decision summary error The execution record should live in the assistant backend, not only in Notion or another external tool. Notion is good for human visibility. It is not ideal as your only execution log. Dedupe Record This prevents duplicate notifications or repeated actions. dedupe key poll id source object id condition version action type delivered at For example: user 456:poll 123:notion page 999:execute:v1 If the same action is attempted again, the system can suppress it. Method 1: Scheduled Polling Worker This is the simplest reliable pattern. A scheduler wakes up every fixed interval and calls a worker. The worker reads the source, updates state, and triggers an assistant action if required. php scheduler - worker - source API - database - assistant action How It Runs The scheduler is responsible for time. It might be cron, a cloud scheduler, a Kubernetes CronJob, or a small internal scheduler. Every interval, it starts a worker run. The worker loads its configuration, queries the target source, compares the result with stored state, and acts if needed. For a simple assistant, this is often enough. A single scheduler and a lightweight worker process can handle dozens of daily checks without requiring queues, leases, or distributed coordination. State Model The scheduler stores very little. Usually it only knows when to trigger a job. The application database stores the important state: poll definition schedule cursor or snapshot last run time failure count status The worker should be stateless. It can hold temporary data while running, but the durable truth belongs in the database. Example Flow Every 10 minutes: trigger Hermes polling worker Worker: load active poll configuration query source compare with previous state run deterministic checks call LLM only if needed update state emit assistant event Best Fit Use scheduled polling workers for: - Daily summaries. - Hourly checks. - Small internal automations. - Simple “watch this” tasks. - Low to medium volume assistant jobs. Weaknesses Scheduled polling is easy to understand, but it can become fragile at scale. If many polls run at the same time, you may overload your workers or hit provider rate limits. Retries can also become messy if the scheduler directly starts the work. Method 2: Queue-Based Polling Workers Queue-based polling is usually the best default for production AI assistants. The scheduler does not execute the poll directly. It puts a job on a queue. Worker processes consume jobs from the queue. php scheduler - queue - worker pool - source API - state store - assistant action How It Runs A scheduler scans for due polls and enqueues jobs. Workers pull jobs when they have capacity. This gives you backpressure. If the system is busy, jobs wait in the queue instead of overwhelming the source API or the LLM provider. State Model The database stores the poll state: poll id user id source ref condition text next run at cursor status failure count The queue message should stay small: { "poll id": "poll 123", "scheduled for": "2026-06-19T01:10:00Z", "attempt": 1 } The worker loads the full state from the database when it starts. Example Flow Every minute: scheduler finds polls where next run at <= now scheduler enqueues jobs Workers: pull jobs from queue lock or lease the poll query the source update state emit assistant action if needed set next run at Best Fit Use queue-based polling for: - Multi-user AI assistants. - Many simultaneous polls. - Integrations with rate limits. - Retriable background work. - Jobs that may take different amounts of time. - SaaS products where reliability matters. Weaknesses Queues add infrastructure. You need dead letter handling, idempotency, visibility timeouts, and retry policies. This is worth it for production systems, but probably excessive for a small prototype. Method 3: External Tool as a Task Queue This is the pattern in the Notion plus Hermes example. The external tool is not just a data source. It becomes the human-facing task queue. The agent periodically checks the tool, claims one task, executes it, and updates the task status. php scheduler - Hermes worker - Notion database - claim one task - execute task - update Notion status How It Runs Every 10 minutes, Hermes queries the Notion database for one task in Todo state. It chooses the next task, usually by priority and creation time. Then it claims the task by setting it to InProgress . After that, Hermes executes the task. If execution succeeds, it marks the task as Complete . If execution fails, it marks the task as Failed or returns it to Todo with a retry count. State Model Notion stores the human-facing task state: Title Description Status: Todo | InProgress | Complete | Failed Priority CreatedAt ClaimedBy ClaimedAt ClaimExpiresAt RunId RetryCount LastError CompletedAt Hermes backend stores the operational execution state: run id notion page id started at finished at execution status tool calls LLM trace error details idempotency key This split matters. Notion is excellent for visibility and manual editing. Hermes backend is better for logs, retries, dedupe, and audit history. Example Flow Every 10 minutes: Hermes wakes up Hermes: query Notion for one task where Status = Todo sort by Priority, CreatedAt update selected task to InProgress set ClaimedBy, ClaimedAt, ClaimExpiresAt, RunId execute the task write execution log set task to Complete or Failed Best Fit Use this pattern when: - Humans already manage work in Notion, Jira, Linear, Trello, or another tool. - You want the assistant to process visible tasks. - The task board is the user interface. - You need a simple human-in-the-loop automation model. Weaknesses External tools are rarely perfect queues. Atomic claims may be limited. Query consistency may lag. Rate limits may apply. If the agent can run in multiple instances, you need a careful claim or lease strategy. The practical recommendation is to use Notion as the human-facing task inbox while keeping all execution logs, retry records, traces, and idempotency keys in Hermes. Notion gives users visibility; Hermes keeps the system reliable. For the dispatcher and concurrency mechanics that sit behind this pattern in Hermes, see Kanban in Hermes Agent for Self Hosted LLM Workflows https://www.glukhov.org/ai-systems/hermes/kanban-in-hermes/ . Method 4: Long-Running Worker Loop A long-running loop is the simplest implementation. while True: due polls = db.find due polls for poll in due polls: run poll poll sleep 30 This pattern combines scheduling and execution in one service, which makes it the simplest possible starting point for background agent work. How It Runs The worker process runs continuously. Every few seconds or minutes, it checks the database for due polls and executes them. It is easy to build, easy to reason about, and fast to iterate on during development. State Model The database still stores durable state: poll configuration next run at cursor last result failure count status The process memory should only contain temporary state: current batch short-lived cache in-flight run Never store important progress only in memory. If the process crashes, any state that was not written to durable storage is gone, and the next run will have no way to know where things left off. Best Fit Use long-running loops for: - Prototypes. - Local development. - Internal tools. - Single-tenant systems. - Low-volume agents. Weaknesses This pattern becomes risky with multiple replicas. Without leases, two workers may run the same poll. It also lacks the operational features of a real queue or workflow engine. A long-running loop is not wrong as a starting point, but it is not a distributed scheduler and should not be treated as one. As soon as you need multiple replicas or stronger reliability guarantees, you will need to move to one of the more structured patterns above. Method 5: Webhook-First With Polling Fallback If the source supports webhooks, use them. Polling should often be the backup, not the primary mechanism. php external system - webhook endpoint - event store - assistant action reconciliation poll - source API - compare with event store - repair missed events How It Runs The external system sends events to your webhook endpoint when something changes. Your system stores the event and processes it asynchronously. A slower reconciliation poll runs every few hours or once per day. It checks whether any events were missed. State Model The event store records incoming webhooks: event id source type source object id event type received at payload hash processed at signature valid The reconciliation poll stores: last reconciliation at last seen cursor last seen version The source object table stores the latest known state: external id current status external updated at last processed event id Best Fit Use webhook-first architecture for: - GitHub events. - Stripe events. - Slack events. - CRM updates. - Deployment notifications. - Ticketing systems. Weaknesses Webhooks require a public endpoint, signature validation, replay protection, and event dedupe. Some providers also send incomplete events, so you may still need to fetch the full object. Even so, if good webhooks exist, polling every minute is usually wasteful. Method 6: Provider-Side Background Job Polling Sometimes the thing being polled is the AI job itself. The application starts a long-running provider job, stores the job ID, and checks later whether it has completed. php app - start AI background job - store provider job id - poll status - fetch result - notify user How It Runs The assistant starts a job with the provider. The provider returns an ID. Your backend stores that ID and checks its status until the job succeeds, fails, expires, or times out. State Model Your backend stores: assistant task id provider job id user id status created at last checked at expires at result ref The provider stores the temporary job state and output. If the output matters, copy it into your own durable storage as soon as the job completes. Provider-side result storage has short retention windows and is not a substitute for a proper archive in your own system. Best Fit Use provider-side background job polling for: - Long AI research tasks. - Large document processing. - Codebase analysis. - Report generation. - Data extraction jobs. - Tasks that exceed normal HTTP request timeouts. Weaknesses This pattern solves one problem: waiting for a long provider job. It does not replace your workflow engine, scheduler, queue, or business state store. Method 7: Durable Workflow Engine A durable workflow engine manages long-running execution, timers, retries, and recovery. Temporal is the most common choice for Go and Python-based assistant backends; for a full implementation guide see Implementing Workflow Applications with Temporal in Go https://www.glukhov.org/app-architecture/integration-patterns/workflow-applications-temporal-in-go/ . Instead of manually wiring every wait and retry, you model the process as a workflow. php workflow engine - activity: check source - timer: wait - activity: evaluate result - activity: notify user How It Runs The workflow starts once and then controls its own waiting. It can sleep for minutes, days, or weeks. If the worker process crashes, the workflow engine can resume from the recorded state. State Model The workflow engine stores: workflow id execution history timer state activity attempts retry policy current workflow state Your application database stores: user-facing poll definition authorization references business records notification records The workflow engine owns process state — execution history, timers, retries, and activity attempts. Your database owns business state — user configurations, authorization records, notifications, and audit logs. Keeping these separate prevents each layer from becoming a confused hybrid of both. Best Fit Use durable workflows for: - Multi-step business processes. - Long-running automations. - Human approval flows. - Reliable retries. - Auditable background work. - Processes that must resume after failure. Weaknesses Workflow engines add concepts and infrastructure. They are excellent when the process is important, but heavy for simple hourly checks. Method 8: Persistent Agent Runtime Some agent frameworks can persist agent state, checkpoint execution, and resume later. This is useful when the agent itself has a multi-step reasoning process. php scheduler or workflow - agent runtime - load checkpoint - call tools - save checkpoint - resume later How It Runs An external scheduler or workflow starts the agent. The agent runtime loads previous state, runs the next step, calls tools if needed, and writes a checkpoint. The agent runtime should not be your only scheduler. It is better treated as the reasoning layer inside a larger backend architecture. State Model Agent checkpoint storage contains: current node messages tool outputs intermediate reasoning state pending action Long-term memory contains: stable user preferences facts project context source references Operational state still belongs elsewhere: poll schedule cursor status retry count dedupe records A useful rule: memory is not a cursor, and a checkpoint is not a queue. Agent memory stores what the model knows; operational state tracks where the process is and what it has done. Conflating the two leads to subtle bugs that only appear under concurrency or after a restart. The full design space for working memory, durable state, and retrieval layers is covered in Memory Systems in AI Assistants https://www.glukhov.org/ai-systems/memory/memory-systems-in-ai-assistants/ . Best Fit Use persistent agent runtime for: - Multi-step research. - Agents that pause and resume. - Human-in-the-loop work. - Tool-heavy reasoning. - Tasks where context accumulates over time. Weaknesses Agent persistence is not the same as operational reliability. You still need scheduling, locking, retries, rate limits, and audit logs. Method 9: Database Sync Plus Change Evaluation In this pattern, polling is used to sync external data into your own database. The assistant then reacts to local database changes rather than querying external APIs directly on every evaluation cycle. php sync poller - external API - local database - change evaluator - assistant action This separates data synchronization from assistant intelligence. The sync worker is responsible for keeping local records current; the evaluator is responsible for deciding what to do about changes. Each layer can be tested, monitored, and scaled independently. How It Runs The sync worker periodically fetches external changes and writes normalized records into your database. A second worker or change stream detects updated rows and decides whether the assistant should act. State Model The sync table stores: external id source type raw payload normalized fields external updated at synced at version content hash The sync state stores: source cursor last sync at rate limit status failure count The assistant evaluation table stores: object id evaluation status last evaluated hash decision notification id Best Fit Use this pattern for: - CRM sync. - Ticketing systems. - Accounting documents. - Product inventory. - Compliance review. - Search indexing. - Internal dashboards. Weaknesses Syncing everything can be expensive and unnecessary. It may also create privacy and retention obligations. Use this pattern when local data has value beyond a single assistant action. Method 10: Adaptive Polling Adaptive polling changes frequency based on state, urgency, or recent activity. active object: poll every 1 minute waiting object: poll every 1 hour stale object: poll once per day completed object: stop polling How It Runs After each run, the worker decides when the next run should happen. If the object changed recently, poll sooner. If nothing has changed for a long time, slow down. If the task is complete, stop. State Model The poll state includes: current interval minimum interval maximum interval backoff policy last activity at priority stop condition The source snapshot includes: status updated at activity level expected next change Best Fit Use adaptive polling for: - Deployment status. - Delivery tracking. - Calendar slot availability. - Price monitoring. - Build jobs. - Long-running provider tasks. - Any source with bursty updates. Weaknesses Adaptive polling can be harder to reason about. If a task must run at a strict time, keep it strict. Do not make compliance jobs clever. Method 11: Semantic Polling With an LLM Evaluator Semantic polling is used when the condition is fuzzy. Code can answer: Is status equal to Complete? Is price below 100? Is there a new message? An LLM can help answer: Does this email sound urgent? Is this customer likely unhappy? Is this research paper relevant? Does this change require my attention? How It Runs The worker first applies cheap deterministic filters. Only candidate items go to the LLM. new item? matches source filters? not already processed? not obviously irrelevant? Then the LLM evaluates the smaller candidate set and returns structured output. { "should notify": true, "urgency": "high", "reason": "The customer reports a production outage." } State Model The poll definition stores: semantic condition examples negative examples user preference summary model config The evaluation log stores: input reference model prompt version structured output confidence cost latency The poll state stores: last seen ids last evaluated hashes last decision last decision reason Best Fit Use semantic polling for: - Important email detection. - Customer sentiment monitoring. - Research alerts. - Sales opportunity detection. - Security triage. - Executive briefings. Weaknesses LLM calls cost money and add latency. They can also be inconsistent if prompts and schemas are loose. Use deterministic filters first. Ask the model only when judgment is actually needed. Decision Table: Choosing a Polling Agent Method | Method | Best Application | Pros | Cons | |---|---|---|---| | Scheduled polling worker | Simple recurring assistant tasks | Easy to build, easy to debug, minimal infrastructure | Limited scaling, basic retries, can overload workers if many polls fire together | | Queue-based polling workers | Production SaaS assistants with many users | Scalable, resilient, supports retries and backpressure | Requires queue infrastructure, idempotency, dead letter handling | | External tool as task queue | Notion, Jira, Linear, Trello based task execution | Human-friendly, easy to inspect, works with existing workflows | External tools are not perfect queues, atomic claim may be difficult | | Long-running worker loop | Prototypes and internal tools | Very simple, fast to implement, few moving parts | Weak reliability, poor multi-replica behavior, limited operational control | | Webhook-first with polling fallback | Event-driven integrations | Fast reaction, fewer API calls, reconciliation catches missed events | Needs public endpoint, event validation, dedupe, provider webhook support | | Provider-side background job polling | Long-running AI provider jobs | Handles slow AI tasks, simple status model, good for async UX | Only manages provider job status, not full business workflow | | Durable workflow engine | Long-running multi-step processes | Strong retries, timers, audit history, recovery after crashes | More infrastructure and concepts, heavy for simple polling | | Persistent agent runtime | Multi-step reasoning agents | Preserves agent context, supports pause and resume, good for tool-heavy tasks | Not a scheduler or queue replacement, still needs operational backend | | Database sync plus change evaluation | Systems where external data has local value | Clean separation, local reporting, fewer repeated external calls | More storage, more sync complexity, possible privacy and retention concerns | | Adaptive polling | Bursty sources or variable urgency tasks | Reduces cost, respects rate limits, reacts faster when activity is high | Harder to reason about, not ideal for strict schedules | | Semantic polling with LLM evaluator | Fuzzy conditions requiring judgment | Handles natural language intent, useful summaries, flexible decisions | Cost, latency, prompt quality risk, should not replace simple code checks | Recommended Default Architecture For most production AI assistants, start with this: php polls table - scheduler - queue - stateless workers - deterministic filters - optional LLM evaluator - notification or assistant action A minimal schema: CREATE TABLE polls id TEXT PRIMARY KEY, user id TEXT NOT NULL, source type TEXT NOT NULL, source ref TEXT NOT NULL, condition text TEXT NOT NULL, schedule type TEXT NOT NULL, interval seconds INTEGER, timezone TEXT, next run at TIMESTAMP NOT NULL, last run at TIMESTAMP, cursor value TEXT, last hash TEXT, status TEXT NOT NULL, failure count INTEGER NOT NULL DEFAULT 0, last error TEXT, created at TIMESTAMP NOT NULL, updated at TIMESTAMP NOT NULL ; CREATE TABLE poll runs id TEXT PRIMARY KEY, poll id TEXT NOT NULL, started at TIMESTAMP NOT NULL, finished at TIMESTAMP, status TEXT NOT NULL, items checked INTEGER, items matched INTEGER, decision summary TEXT, error TEXT ; CREATE TABLE notifications id TEXT PRIMARY KEY, poll id TEXT NOT NULL, user id TEXT NOT NULL, dedupe key TEXT NOT NULL, title TEXT NOT NULL, body TEXT NOT NULL, delivered at TIMESTAMP, UNIQUE dedupe key ; This gives you a clean separation: scheduler owns time queue owns buffering worker owns execution database owns state LLM owns semantic judgment assistant owns user interaction That separation is the heart of a reliable polling agent. Example: Hermes Agent Processing Notion Tasks Now let us apply the architecture to a concrete case. Assume a Notion database contains tasks. Hermes should run every 10 minutes, take one task in Todo state, set it to InProgress , execute it, and then mark it Complete . This is best described as: external tool as task queue + scheduled polling worker + claim or lease based execution For a production version, it becomes: queue-based polling with Notion as the human-facing task inbox Notion Task Properties The Notion database should contain fields like: Name Status: Todo | InProgress | Complete | Failed Priority CreatedAt ClaimedBy ClaimedAt ClaimExpiresAt RunId RetryCount LastError CompletedAt The important fields are ClaimedAt , ClaimExpiresAt , and RunId . They make the task claim visible and recoverable. Hermes Execution State Hermes should also keep its own execution record: run id notion page id started at finished at status input snapshot tool calls result summary error idempotency key This protects you if Notion is edited manually, if an API call fails, or if you need to audit what Hermes actually did. Execution Flow Every 10 minutes: Hermes scheduler creates a run Hermes worker: finds one Notion task where Status = Todo sorts by Priority and CreatedAt claims the task by setting Status = InProgress writes ClaimedBy, ClaimedAt, ClaimExpiresAt, and RunId executes the task writes execution logs to Hermes backend sets Notion Status = Complete on success sets Notion Status = Failed on failure If Hermes crashes after claiming a task, the lease can expire: Status = InProgress ClaimExpiresAt < now A future run can then recover the task or mark it as failed. Failure Handling On success: Status = Complete CompletedAt = now LastError = empty On recoverable failure: Status = Todo RetryCount = RetryCount + 1 LastError = short error message On non-recoverable failure: Status = Failed LastError = clear explanation For safety, Hermes should also use an idempotency key: notion page id + task version + action type This prevents the same task from being executed twice if a retry happens at the wrong time. Why This Is Not Just Polling The polling part is only the wake-up mechanism. The real architecture is task claiming and reliable execution. A naive implementation says: Every 10 minutes, find a Todo task and do it. A reliable implementation says: Every 10 minutes, claim exactly one eligible task, record the run, execute idempotently, and move the task to a terminal state. That is the difference between a demo and an agent you can trust. Common Polling Agent Mistakes Mistake 1: No Claim Protocol If two workers can see the same task, they can both execute it. Use: ClaimedBy ClaimedAt ClaimExpiresAt RunId Even if you currently run one worker, design as if a second worker might appear later. Mistake 2: No Dedupe Key Every external action should have a dedupe key. user id + poll id + source object id + action type + condition version This prevents repeated notifications, repeated emails, repeated task execution, and repeated tool calls. The broader principles behind scoping, storing, and testing these keys apply equally here — see Idempotency in Distributed Systems That Actually Works https://www.glukhov.org/app-architecture/integration-patterns/idempotency-in-distributed-systems/ . Mistake 3: Calling the LLM Too Early Do not ask the model to do database filtering. Bad: Send all tasks to the LLM and ask which one is Todo. Better: Use the Notion API filter to fetch Todo tasks. Then use the LLM only if task interpretation is needed. Mistake 4: Treating Notion as the Only Backend Notion is a good human interface. It is not a complete execution backend. Keep execution logs, retries, traces, and idempotency records in Hermes. Mistake 5: Infinite Polling Every poll should have a stop condition. Examples: stop after success stop after date stop after max retries stop when user disables it stop after repeated authorization failure A polling agent without a stop condition is a quiet cost leak. Mistake 6: No Observability You should be able to answer: What did the agent run? Why did it run? What did it read? What did it change? Why did it fail? Did it notify the user? Did it run twice? If you cannot answer those questions, the system is not ready for important work. Observability Checklist Track metrics such as: polls due polls started polls succeeded polls failed tasks claimed tasks completed tasks failed claim expired count duplicate suppressed count llm calls llm cost rate limit count average run duration Log fields such as: poll id run id source type source object id claim id cursor before cursor after decision dedupe key error Build an admin view for: active polls stuck InProgress tasks recent failures high retry tasks dead letter jobs expensive LLM evaluations disabled integrations Polling agents run in the background, where failures are quiet and problems can compound before anyone notices. Background systems need visibility built in from the start, not added as an afterthought when something goes wrong. For the full observability stack for AI and LLM-backed systems — metrics, traces, structured logs, and SLOs — see Observability for LLM Systems: Metrics, Traces, Logs, and Testing in Production https://www.glukhov.org/observability/observability-for-llm-systems/ . Final Recommendation For a serious AI assistant, start with queue-based polling workers and a durable state store. Add webhooks where providers support them. Use adaptive polling when rate limits matter. Use a durable workflow engine when the process is long-running and multi-step. Use persistent agent runtime when the agent needs to reason over time. For the Hermes and Notion example, the right architecture is: Notion as the human-facing task inbox Hermes scheduler every 10 minutes Hermes worker with claim or lease logic Hermes backend for execution logs and idempotency Notion status updates for visibility The polling interval is not the hard part. The hard part is making sure the agent claims one task, runs it once, records what happened, and leaves the system in a state humans can understand. That is what turns a polling script into a reliable AI assistant — not the interval, not the model, but the discipline around claiming work, recording it, and leaving the system in a state that humans and future runs can both understand.