Full Pro free for 7 days, no credit card. Start free →
← All posts
September 24, 2026 · 5 min read

The "Already Handled" List: How to Stop Your AI Agent From Re-Processing the Same Items Every Run

Target query: how to stop scheduled ai agent redoing the same work Slug: agent-completion-ledger-stop-redoing-work Published: 2026-09-23 Surface: vilix.ai blog (Ghost) (this version) Companion piece (dev.to, full rewrite): scheduled-agent-memory-of-done-completion-ledger.md * dev.to: TBD * vilix.ai blog: TBD The "Already Handled" List: How to Stop Your AI Agent From Re-Processing the Same Items Every Run A prospect gets the same follow-up email twice in three days, because Wednesday's run

Target query: how to stop scheduled ai agent redoing the same work Slug: agent-completion-ledger-stop-redoing-work Published: 2026-09-23 Surface: vilix.ai blog (Ghost) (this version) Companion piece (dev.to, full rewrite): scheduled-agent-memory-of-done-completion-ledger.md

  • dev.to: TBD
  • vilix.ai blog: TBD

The "Already Handled" List: How to Stop Your AI Agent From Re-Processing the Same Items Every Run

A prospect gets the same follow-up email twice in three days, because Wednesday's run has no idea Monday's run already sent it. The prospect does not think "stateless execution." The prospect thinks the company is sloppy.

Past the demo stage, this is the failure mode: the agent does good work, then forgets it did the work. Every run opens with a question it cannot answer alone: did I already do this?

Why automation agents are especially bad at this

Three things conspire against the scheduled agent.

Runs are stateless. An execution starts, pulls its inputs, and ends. Nothing inside the run survives into the next one unless someone deliberately persists it. The agent is not forgetful; it was never given the chance to remember.

Storage is per-tool. The n8n workflow remembers what the n8n workflow did; the Make scenario remembers what it did. The two never compare notes. When two agents touch the same leads or tickets, each one's "processed" list is a private diary the other cannot read.

Items have no stable identity. The agent fetches "the 20 newest support tickets" every morning, but tickets get renumbered, retitled, or merged between runs. Identify work by subject line or list position and the same ticket looks new the moment its appearance changes.

Fix identity, storage, and statelessness together and the duplicates stop. Fix only one and they come back in a different form.

Anatomy of a completion record

The core unit is a small record that says one thing: this action already happened to this item. Five fields cover almost every case:

  • Item key: the stable identifier. Ticket ID, thread ID, record ID, a hash of the row's canonical fields. Never a subject line, never a list position.
  • Action: what was done. Replied, enriched, scored, filed, sent. Generic "processed" entries cause trouble later, because "processed" means something different to every workflow that reads it.
  • Timestamp: when it happened. Expiry math needs this, and debugging duplicate-sends without it is miserable.
  • Outcome: what the tool reported. Sent, queued, failed, bounced. This is the field that separates a real ledger from a wish list.
  • Run reference: which execution wrote the record. When something goes wrong at 3 AM, this is how you trace it back to the run that wrote the entry.

That is the whole first-version schema. Most scheduled duplicates are exact duplicates: the same item, the same action. A simple key lookup catches them; add complexity later, if ever.

One ledger, or it does not work

The single most common reason a completion record fails in production is that it lives in the wrong place: inside one workflow.

Two agents touch the same ticket queue: a morning triage agent in n8n and an evening follow-up agent in a scheduled script. Triage keeps its done-list in the workflow's static data, which follow-up cannot read. So follow-up re-sends what triage already handled, and both ledgers are technically correct.

The completion record has to live somewhere every agent reads before acting, and a shared memory layer is the natural home. Vilix AI connects agents over MCP, so the n8n agent, the scheduled script, the Make scenario, and a chat assistant in Claude or Cursor all read and write the same store. One ledger, one truth, across every tool.

Cloud-hosted, so there is no database to provision. Retrieval is recency-aware with last-write-wins handling, so the next run sees the newest record: when the truth changes, say it once and every connected agent gets the update.

Deciding when "done" expires

A done-list without expiry becomes a different bug: the agent refusing to do work it should do again. The expiry should follow the action, not the item:

  • Outreach and follow-ups: measured in weeks or months. A prospect emailed 90 days ago with no reply is a new outreach decision, not a duplicate.
  • Triage and routing: tied to the item's state. Retag the ticket and the old triage record is obsolete; the agent should decide fresh.
  • Enrichment and scoring: tied to the source data. Refresh the lead data and the enrichment record goes stale with it.
  • Irreversible sends: reports, filings, customer-facing messages. These keep the longest memory, because re-doing them is the most visible failure.

The timestamp and outcome fields make expiry decisions possible. "Emailed 90 days ago, no reply" and "emailed yesterday, bounced" are both "done," but they mean different things for today's run. A flag-only ledger cannot tell them apart.

The two traps that survive the ledger

Recording intentions instead of outcomes. If the agent writes "email sent" while the API call actually failed, the ledger protects a lie: every future run skips the email that never went out. The write happens after the tool confirms success, not when the agent decides to act.

No human gate on destructive actions. A perfect done-list can record a terrible action perfectly. The ledger answers "did I already do this," never "should I do this." Refunds, deletions, and anything customer-facing keep a human approval step. Memory makes the agent consistent, not wise.

Both traps share a root cause: trusting the agent's narrative over the world's evidence. The ledger works when written from tool results and read as a lookup, not as the agent's story about itself.

A checklist before next week's runs

If duplicates are eating your mornings, this is the order of operations:

  1. Give every work item a stable key. No subject lines, no list positions.
  2. Write one completion record per action, with the five fields above.
  3. Put the ledger in shared memory every agent can read, not inside one workflow.
  4. Add expiry by action type, and record enough outcome detail to make expiry decisions.
  5. Write records from tool results, after success is confirmed.
  6. Keep human approval on anything destructive.

Shared memory turns this from a per-workflow hack into infrastructure: write the pattern once, and every agent in every tool stops re-doing finished work. The free plan proves it on one workflow, the 7-day Pro trial needs no credit card, and your data stays portable, exportable or deletable anytime.

Try Vilix Pro free for 7 days

Persistent memory across ChatGPT, Claude, and the AI tools you already use in Vilix AI.

Start 7-day free trial
Keep reading
Your AI Agent Remembers Everything and Still Gets It Wrong

Target query: why does my ai agent forget even with memory enabled Slug: ai-agent-memory-vs-state-scheduled-automations Your AI Agent Remembers Everything and Still Gets It Wrong Picture this. You did everything right. Your scheduled agent stores full conversation history between runs. Every morning the workflow loads yesterday's runs, the corrections, the context. The memory system works. And yet, Tuesday morning your support agent tells a customer their refund is still pending, when the fin

Why Does Your AI Agent Give a Different Answer Every Time? Fixing Output Drift in Scheduled Automations

Target query: why does my ai agent give a different answer every time Why Does Your AI Agent Give a Different Answer Every Time? Fixing Output Drift in Scheduled Automations Your lead-triage agent runs at 7 AM every weekday. Monday it summarizes new leads in a tight bullet list. Tuesday the bullets are back, but the scoring scale quietly changed from 1-5 to 1-10. Wednesday it invents a whole new format with emojis. The prompt did not change. The workflow did not change. The agent just drifted

Stop Throwing Away the Transcript: How to Keep Conversation History for Scheduled AI Agents

Target query: how to keep conversation history for scheduled AI agents Slug: keep-conversation-history-scheduled-ai-agents Published: Stop Throwing Away the Transcript: How to Keep Conversation History for Scheduled AI Agents Every scheduled agent run throws away the most valuable thing it produced: the conversation itself. Think about what a run actually looks like. A morning triage agent in n8n wakes up, reads yesterday's leads, reasons through which ones are worth a follow-up, drafts the