The 8am problem: what breaks when an agent has to keep an appointment A developer who has argued that scheduling is the interface of an AI agent, not a bolted-on feature, details the four failure modes that emerge when an agent must deliver a recurring commitment like an 8:00 daily brief for a year: time zones, partial failure, duplicates, and the difference between watched and unwatched tasks. The account describes a brief that arrived at 8:40 on the second Tuesday with correct content but no record of why it ran late, and argues that a schedule must be stored as a user-local rule resolved server-side at fire time rather than as a timestamp, with the retry ladder computed backwards from the deadline. Ask someone what their AI product does while they are asleep and you usually get the same answer: it keeps running. Which is true, and also where the interesting part starts, because "keeps running" is not the hard bit. The hard bit is that it promised. A reminder fires or it doesn't; nobody dwells on it. A brief is different. If you told a tool that you want the thing waiting for you at eight, then eight is an appointment. A late brief is not a slow brief. It's a missed one, and you notice, because you were holding a coffee and a minute of attention open for it. I've argued before that a schedule is not a feature bolted onto an agent, it is the interface. This piece is the follow-up I owed that claim: the four things that actually bite once you take "8:00, every day, for a year" literally. Time zones, partial failure, duplicates, and the difference between a task someone is watching and a task nobody is. The failure that taught us the most wasn't dramatic. It was the second Tuesday. The brief arrived at 8:40. Correct content, reasonable length, one of its items even useful. On a demo that looks like a pass. On a morning routine it's worse than nothing, because the entire reason to read a brief is that it competes with the coffee, and by 8:40 the coffee is gone and the commute won. Worse: nobody could say why . The system had done the work. There was no error to look at. The honest answer was "it took the long way round," and there was no record of the long way round — so the only thing we could have told the user was a story. That's the first thing that gets decided for you: what your system can say about a run after the fact is part of the product. Everything else below is downstream of taking that seriously. The natural move is to store the schedule as a timestamp. It is also wrong in a way that stays hidden for months. A schedule is not a moment; it is a rule. And a rule has an owner, and the owner moves. They change time zones on a flight, they spend a month in another country, their clocks go forward and back twice a year on dates the rest of the world doesn't share. If "8:00" lives as a stored instant, every one of those events silently turns into a different local time. The user doesn't report it as a bug. They just notice one morning that the thing arrives while they're already in the car. So the configuration has to be expressed in the user's local terms, and resolved on the server at the moment it fires. That sounds like a one-line change and is not, because the moment you store a rule instead of an instant you inherit every question the rule implies: None of these have a universally right answer. All of them have a wrong answer, which is the one where the system picks something and doesn't tell anyone. And under all of it sits a rule that doesn't have a clever solution: if you said eight, 8:40 is a bug. Compute the ladder backwards from the deadline — how long the work can take, how long a retry can take, what has to be abandoned rather than allowed to run late — and accept that a late delivery and a missing delivery cost you the same trust, roughly. Here's the one nobody puts in the architecture diagram, because it isn't visible in a demo. A task that runs once can be allowed to be a straight line: start, work, finish. A task that runs at eight every morning for a year is a recurring commitment , and recurring commitments are only as good as what happens when one of them is cut in half. The cut comes from all directions. A process gets restarted. A step is slow and gets given up on. A run is resumed from a checkpoint written before the last part finished. An exploration step that was cancelled halfway left something behind. If the design assumes "attempts are clean," then the morning the system recovers from a hiccup is the morning the user gets the same section twice. What we came to treat as the real requirement is not retrying. It's being able to say, of a run that got halfway, what was and was not already delivered — and to finish the rest without doing the visible half again. That is mostly bookkeeping, and it is the part that has cost us the most. You cannot bolt it on later; by then the assumptions about "an attempt" are in every layer. Worth naming the shape out loud: for a one-off request you can be sloppy about identity, because a human is watching and can say "no, not like that." For a daily task, the user is not there, and the default has to be that repeating work is harmless. That's the whole bar. There's a second-order effect that took us longer to see. Once a task is recurring, its own history becomes an input . "Anything new since yesterday" is a completely different computation when there is a yesterday to compare against, and the comparison only holds if the previous run's record is intact and trustworthy. Which means the ledger you keep for your own debugging turns out to be load-bearing for the product's output. If yesterday's record is missing, the honest answer is "I can't tell what's new" — and you have to be willing to say that, rather than quietly produce a brief that looks like every other one and hope nobody notices the overlap. The nasty version of this is when two runs of the same task overlap. Start Monday's run late enough and it can still be going when Tuesday's is due. That is a policy decision, not a bug fix: does the new one wait, does it preempt, does it run anyway? Any of those can be right. What cannot be right is discovering the answer by watching two of them write to the same output. Every piece of guidance you give a scheduled task is permanent in a way a prompt isn't. In a chat, a slightly wrong instruction costs you one bad answer and you rephrase. In a recurring task, it costs you a bad answer every morning until somebody notices — and the person most likely to notice is the person you were trying to help. So the loop that matters isn't "make the output better this once." It's the much duller one: notice the recurring flaw, and change the standing configuration so the flaw can't recur. The measure of whether a scheduled agent is working is not how good this morning's brief was. It's how rarely you have to say the same sentence twice. When someone is in the room, failure is cheap. They see the thing stall, they hit it again, the second attempt is fine, and the failed attempt evaporates with no cost to anyone. This is why so much tooling gets built around the assumption that a human will notice. Unattended, that assumption is gone, and it takes a decision with it: the system is now allowed to make choices the user never sees. Retry this? Skip that? Finish late, or hand over something narrower that's still on time? Whatever it picks, the user's only access to what happened is what the system chooses to show them. Which turns out to be a honesty problem wearing an engineering costume. An unattended product that quietly shows the polished version of what it did is training its users to trust a story instead of a record. If the run took the long way round, the write-up should say so — not as an apology, just as a fact, in the same register as everything else. We would rather hand over the awkward detail than a clean shape that doesn't match the file. The useful test is a bit uncomfortable. Read your own run history and ask whether it is a record you can reconstruct a run from — someone who wasn't there should be able to see what ran, what it decided, what it gave up on, and what it delivered. If the answer is "mostly, if you know the system," it's a log. If the answer is "yes, obviously, from the record alone," it's a product. CloudPal runs these tasks on our machines — no installation, nothing using your laptop, nothing reading files you already have; it's a cloud agent that keeps a schedule and hands back a finished document. You say what you want in one sentence and when you want it, and the result shows up as a document you can forward rather than an answer you have to reassemble. Being straight about the boundaries: the brief is compiled from public sources, ordered, and written. The value is in the part that accumulates — the second week needs less explaining than the first, because it has learned how you like things arranged and which parts you actually read. That's the claim worth testing, and it's testable: give it the same kind of task twice, two weeks apart, and see whether the second one needed fewer sentences. It's in limited preview. New accounts get a dollar of credit, which is enough to run something real, and the number of new accounts per day is capped. If you want to judge it as an engineer rather than as a user, the question I'd put to it is this one: let it run for a fortnight and then go looking for the morning it took the long way round. If you can find it, and it told you, the boring parts are probably real. CloudPal.TuringCorp.net https://CloudPal.TuringCorp.net — create an Agent Pass, sign in, and say what you want done. Earlier in this series: what an always-on agent forced us to build https://dev.to/turingcorp/we-built-an-ai-agent-that-runs-in-the-cloud-on-a-schedule-and-hands-you-the-finished-file-22pc .