The agent confirmed it set the reminder. The reminder never fired.
A scheduled job has two legs, it fires and it delivers, and confirming the first lies about the second.
Apollo Space Research
Apollo Space
“Done, I’ll remind you Thursday at 9.” The message lands, the user closes the tab, and the whole arrangement feels finished. Thursday at 9 comes. Nothing arrives. The user finds out at 9:40, in a hallway, when the person they were supposed to ping asks why they went quiet. The agent was not lying when it said done. It really did write the reminder down. It just never owned the moment the reminder was supposed to leave its hands.
That gap, between I scheduled it and it actually reached you, is where most “proactive” software quietly fails.
A scheduled job has two legs: it fires and it delivers. Confirming the first lies about the second.
This post is about why those two legs come apart, why a cheerful confirmation makes the failure worse instead of better, and how we wire a reminder so the agent is on the hook for the part that actually matters, the arrival.
The naive version: a reminder is a row you write down
The obvious way to build a reminder is the way it feels from the outside. Someone asks for a nudge on Thursday. The agent writes a row somewhere, a time, a message, a user, and replies that it’s set. The work, as far as the conversation is concerned, is over.
This is satisfying because it maps to how a person makes a promise. You say “I’ll remember,” and saying it feels like doing it.
But writing the row is only the first leg. A scheduled job has two legs: it fires and it delivers. The row sitting in a table is a plan to act, not an act. Something still has to wake up at the right minute, notice the row is due, and push a real message through a real channel to a real human who is, hopefully, looking. The agent confirmed the plan. It said nothing about the delivery, because at the moment it spoke, the delivery hadn’t happened and couldn’t have.
Here’s the quiet trap. The confirmation arrives in the exact place where the failure will later be invisible. The user reads “done,” and from that second on, they assume the system has it. They stop holding the reminder in their own head, which is the entire point of asking for one. So when Thursday’s message never fires, there is no backup human attention to catch it, because the confirmation already told them to let go.
A reminder that confirms the write but not the send isn’t a reminder. It’s a way to make someone stop worrying about the exact thing that’s about to break.
Why the second leg breaks so often
The second leg fails for reasons that have nothing to do with the agent being smart or dumb. They’re the unglamorous reasons every team that has ever shipped a scheduler knows by heart.
The waker-upper has to actually run. Some background worker has to poll for due jobs, on time, forever, and background workers are the most forgettable part of any system. They die quietly. They fall behind. They come up in a different timezone than the one the row was written in, so “Thursday at 9” becomes Thursday at 9 somewhere nobody lives. None of that surfaces in the chat where the promise was made. The conversation looks healthy right up until the moment of truth.
Then there’s the channel. Firing the job is not the same as the message landing. The push can be sent into a session that closed. The email can route to a place nobody checks. The notification can be generated perfectly and swallowed by a permission the user revoked three weeks ago. The job fired, a log somewhere even says so, and the human still heard nothing.
A job that fired and a human who heard are two different facts, and only the second one is the reminder.
This is the part worth sitting with. In a normal program, you can sometimes get away with conflating “I emitted the event” and “the event was received,” because a downstream system will retry or complain. A human at 9am on Thursday is not a downstream system. They don’t retry. They don’t throw an error you can catch. They just don’t get reminded, and they find out the slow, expensive way, in the hallway, at 9:40, from someone else.
The naive fix: make the agent double-check by re-confirming
The first instinct, once you’ve been burned, is to make the agent more reassuring. Have it confirm harder. “Reminder set for Thursday at 9, I’ve double-checked, it’s in the system.” Maybe have it re-state the reminder back, read out the time, spell the timezone.
This feels like rigor. It is decoration.
Re-confirming the write a second time does not touch the second leg at all. The agent is still standing at the moment of scheduling, narrating the plan with more confidence, while saying exactly nothing about the moment of arrival that hasn’t happened yet. You have made the promise louder. You have not made the delivery more likely. If anything you’ve made the eventual silence more jarring, because the user trusted the extra reassurance and let go even harder.
A confident agent describing a future action is still just describing it. The check that matters cannot be performed at the time the reminder is set, it can only be performed at the time the reminder is supposed to fire. Any amount of double-checking at write-time is checking the wrong leg twice.
That’s the whole reason this problem is sneaky. The natural place to add reassurance is the conversation, and the conversation happens days before the only moment where reassurance could be earned.
Our way: own the arrival, not the intention
The fix is to move the agent’s accountability from when it speaks to when the message is supposed to land. The reminder isn’t done when the row is written. It’s done when a human is confirmed to have been reached, and if they weren’t, the system has to know, and try again, and tell someone it’s struggling.
So we build the reminder as a loop with a closing condition, not a row with a confirmation.
Walk the legs in order. The first leg is the same as the naive version, the agent writes the job: the time, the message, the person, the timezone made explicit so “9” means 9 where the human actually is. The honest part is what the agent says back: not “done, you’ll be reminded,” but “scheduled, I’ll confirm when it actually goes out.” It promises the thing it can keep, and defers the claim it can’t yet make.
The second leg is the one we refuse to leave unattended. A worker wakes at the due minute, finds the job, and fires the message through a channel. Then it waits for a signal that the message was actually received, a delivery acknowledgment, a session that was open, a read, something that distinguishes “I sent” from “they got it.” If that signal comes back, the loop closes and the agent can finally make the claim it deferred: this reached you, here is when. That second message, the one after the arrival, is the only honest confirmation in the whole sequence.
And when the signal doesn’t come back, the system does the thing the naive version structurally cannot. It treats the silence as a problem to solve, not a job to mark complete. It retries. If the first channel stays dark, it escalates to a different one, the push didn’t land, so try the email; the email bounced, so try the place the user is actually live right now. And if every channel comes up empty, it does not quietly file the job as “fired” and move on. It raises its hand. A reminder that couldn’t reach its human is a small failure that announces itself loudly, while it’s still small, instead of being discovered in the hallway at 9:40.
A scheduled job has two legs: it fires and it delivers. We don’t let the agent confirm the first until it has watched the second.
What this costs, and what it buys
This is more expensive than a row and a thumbs-up, and the trade is worth naming plainly.
It costs a standing loop. The job can’t be fire-and-forget; something has to wait for the delivery signal, hold the retry budget, and own the escalation path. That’s more moving parts than “insert a row, reply done.” We pay it on purpose, because the cheap version isn’t cheaper, it just moves the cost downstream onto a human who finds out late, and a late reminder in real operations is rarely a small thing. The whole reason someone delegates a nudge is that the moment it guards matters more than they can afford to track themselves.
What it buys is that the confirmation finally means something. When this system says reminded, a human was reached, that word is now a fact about an arrival, not a hope about a write. And the failures that used to hide until the worst possible minute now surface at the moment they happen, addressed to someone who can do something about them, with the full context of which job, which channel, which person. The promise and the proof live on the same leg.
The turn
Ask yourself what you’re actually buying when you ask a person to remind you of something.
It isn’t the notebook. It isn’t the sticky note or the calendar entry, those are leg one, the write, and any tool can do leg one. What you’re buying is leg two: a second mind that will carry the thing across the gap of days and make sure it actually reaches you, and that will come find you if it can’t. The whole value of “I’ve got it” is the part where, if something goes sideways at 8:55 on Thursday, the person who said it scrambles to reach you anyway, instead of pointing at a row in a table and saying well, technically I scheduled it.
That second leg is what trust is made of, and it’s the leg no confirmation message can fake. You don’t trust a colleague because they wrote your reminder down. You trust them because, the one time the usual channel failed, they texted, then called, then caught you in person, because reaching you was the job, and sending was never enough. A system earns the same trust the same way: by being accountable to the arrival, not to the intention.
A scheduled job has two legs: it fires and it delivers. The agent that only confirms the first is a colleague who promises to remember and then, the morning it counts, is nowhere.
That’s what we’re building at Apollo Space: software that’s accountable to the moment the message lands, not the moment it was promised, that watches its own reminders all the way to a human and raises its hand when it can’t. If you’ve ever been let down by a “done” that turned out to be only half a job, you already know which leg you were trusting.
Apollo runs your company's repetitive ops so your team doesn't.
Join the waitlist for early access, founding-user pricing, and a front-row seat as we ship.
Join the waitlistThe hidden tax of parallel agents is a migration diamond
Six agents writing to one schema conflict in the database, not the code, and CI dies at "multiple heads."
EngineeringAn orchestrator that can't survive its own crash isn't one
A crash that erases the orchestrator's reasoning loses the one thing you can't rebuild.
EngineeringPut a deterministic gate in front of your smartest reviewer
The cheapest defect-catch is a dumb script that checks two merged branches still boot before any judgment.