---
title: The Nudge Queue: Reminders Run by a Dispatcher With No AI
description: How to make every reminder a file or row that a dumb, deterministic script owns — so an LLM can schedule but never fire.
track: contributed
url: https://www.chiefofstaff.io/guides/contributed/the-nudge-queue
published: 2026-09-10
contributor: Carmen Ashley (owner: Frederic Haddad)
outcome: hand every “remind me” to a queue file that a dumb, standard-library dispatcher fires on a per-minute tick — so the model enqueues and never fires.
source: chiefofstaff.io
---

# The Nudge Queue: Reminders Run by a Dispatcher With No AI

How to make every reminder a file or row that a dumb, deterministic script owns — so an LLM can schedule but never fire.

## The problem

Reminders are the first thing people delegate to an AI chief of staff, and the first thing that quietly breaks. Delegating "remind me at 6pm" to an LLM session has three failure modes. **Expensive:** every check burns a model call, even the 99% of checks where nothing is due. **Flaky:** the session may misread the date, drift on timezone, or fire twice because it wasn't sure whether it already fired. **Silently forgetful:** an LLM with no persistent state doesn't *hold* a reminder — it re-derives it from whatever context it can find, and when the context is gone, the reminder is gone, and the principal never learns it was missed. The worst outcome isn't a late nudge; it's a nudge that was never scheduled at all, discovered the next time the thing it was supposed to prevent goes wrong.

Nudging is not a reasoning problem. It is deterministic work: read a queue, compare timestamps, send what's due, record what you sent. That is exactly the work you should never give to a model.

## The philosophy behind the choice

**Nudging is deterministic work, so it runs on no AI.** A plain script — standard library only, no model, no network calls beyond the send — runs every minute. Nothing due? Silent exit in milliseconds. Due item? Send it. That's the whole dispatcher. The per-minute cost is negligible, there is nothing to drift, and "it forgot" is not a sentence that can be formed about a script that reads a queue.

**The LLM enqueues; it never fires.** This is the load-bearing separation. When the principal says "remind me on the 15th," the AI's job is *translation* — turning natural language into a well-formed queue entry, with the right venture label and a concrete action in the title. Firing is a different job with a different risk profile (a wrong send is externally visible), so it stays entirely with the script. One writer, one firer, and the firer is the dumber of the two. This also means a reminder, once enqueued, does not depend on any session staying alive: it's a file on disk that outlives every conversation.

**Recurring nudges are data, not code.** "Gym on Tue/Thu at 5:50pm" or "payday report on the last day of the month" are not scripts to install and maintain — they are declarative entries with a recurrence pattern. The pattern language is deliberately bespoke and human-readable (weekday lists, `daily`, day-of-month, `last-day`, nth/last weekday of month) rather than cron syntax, for two reasons: standard cron cannot express "last day of the month" or "third Sunday" anyway, and the principal must be able to read the pattern in plain view. Each occurrence is deduped by an audit record so nothing fires twice.

**Receipts, retries, and honesty about lateness.** Every fired nudge leaves a receipt (the fired entry moves to a fired folder with a best-effort audit commit). Failed sends stay queued and retry automatically. A nudge missed while the machine slept fires on wake, marked late — the "(late)" prefix is a small honesty feature that matters more than it sounds. No silence, no silent drops.

## How it's wired at a high level

**The queue.** One-shot nudges are plain files in a queue folder, named with a sortable timestamp and slug: `YYYYMMDD-HHMM-<slug>.txt`, local time. The file body *is* the message — sent verbatim when due. A special body marker (`#wake`) means "when due, batch everything into one headless AI session" instead of sending a plain message, so a morning wake-up collects all its items into one run.

**Recurring nudges.** A second folder holds standing entries: one or more `when:` header lines plus a body with the same plain/`#wake` semantics. Patterns like `tue,thu 17:50`, `daily`, `day-15`, `last-day`, `3rd-sun`, `last-fri` cover weekday lists, fixed days, month boundaries, and nth-weekday-of-month. Each computed occurrence is deduped against the fired audit records, and misses older than a catch-up window (24 hours here) drop as stale rather than firing absurdly late.

**The dispatcher.** One OS scheduler job, installed exactly once by the human (the AI never installs schedules — that authority line matters), ticks every 60 seconds and runs the script. The script: collect due one-shots and computed recurring occurrences; if none, exit silently (zero AI, zero network); if any, send plain files verbatim, group `#wake` items into one headless session, move everything to `fired/` with an audit commit. Never two AI workers at once — if the triage lock is held, the batched session defers whole. The script should be testable with a fake "now" so recurrence patterns can be dry-run without waiting for the actual date.

**Receipts and failure handling.** A fired entry in `fired/` with a timestamp is the receipt — it doubles as the dedup key for recurring occurrences. Failed sends never leave the queue. Git-commits that collide with other activity skip silently and are swept by a later session, an accepted tradeoff in exchange for the queue living in the same auditable vault as everything else.

**What this removes:** per-reminder scheduled jobs, "arming" commands the principal must paste, and any design in which a reminder's existence depends on a chat session remembering.

## What a reader's chief of staff should be able to do afterwards

- **Guarantee that every "remind me on X" becomes a queue entry** a dumb reliable script owns — and show the entry, not promise it.
- **Enforce the separation:** the AI writes queue files; the script is the only thing that fires. Be able to explain why a model should never send a scheduled message.
- **Read and write the recurrence patterns:** weekday lists, `daily`, `day-N`, `last-day`, nth/last weekday of month — and dry-run them against a fake clock before trusting one.
- **Design the receipt trail:** fired-folder entries as both proof-of-send and dedup key, retry-on-failure, and late-fire marking with an explicit staleness cutoff.
- **Keep the dispatcher boring:** stdlib-only, per-minute tick, silent exit when idle, one supervisor job installed once — with a written kill switch (misfire, duplicate, or dropped nudge → revert to the previous scheme).

The end state: the principal never arms a reminder, never wonders whether one was set, and can audit months of nudges in a folder of fired receipts — with the AI doing the one part it's good at (understanding what "the third Sunday" means) and the script doing the one part it's good at (actually firing, every minute, forever).