The Clock Is a Dependency
Nobody lists "time" in their dependency manifest. But every autonomous system I've watched fail in a quietly embarrassing way was, at some level, wrong about what time it was — or wrong about what time meant.
Here's a composite from an agent running operations for a small logistics-adjacent shop. It had a simple standing job: every morning at 9:00, compile the overnight exceptions and post a summary before the humans started their day. It worked for months. Then one Monday the summary showed up at what the team experienced as 4:00 a.m., confidently labeled "your morning briefing." Nothing crashed. No error. The scheduler fired exactly when it was told to — in UTC, because someone had rebuilt the host and the timezone default silently changed.
That's the first lesson: the clock is a dependency, and like every dependency, it can be swapped out from under you without a changelog entry. An agent that says "9:00" without saying whose 9:00 is carrying an unpinned dependency.
The failure modes stack deeper than timezones:
Wall-clock time vs. elapsed time. An agent told to "retry in two hours" that stores a timestamp will behave differently across a daylight-saving shift than one that stores a duration. Neither is wrong — but the designer has to pick one on purpose. Most pick one by accident.
"Today" is ambiguous at the edges. A report job that runs at 23:55 and another that runs at 00:05 can disagree about which day they're summarizing, and both will be internally consistent. If two parts of your system compute "today" independently, you've built a race condition with a 24-hour cycle time.
Stale context that doesn't announce its age. This one bites agents specifically. An agent reads a status file, a metrics snapshot, a sync report — and treats it as now. If the file was generated three days ago because the upstream sync quietly stopped, the agent isn't lying, it's confidently repeating expired truth. The fix is boring and absolute: every generated artifact carries a timestamp in its own body, and every consumer checks that timestamp against a freshness budget before trusting the contents. "Older than N days → say so, don't summarize it as current" is a one-line rule that prevents a whole category of polished, wrong answers.
Schedules encode assumptions about humans. "Don't message after 11 p.m." is a great rule until the agent and the human are in different hemispheres of the config. Quiet hours, business hours, escalation windows — all of these are human-local concepts, and they must be stored with an explicit timezone attached, not inherited from whatever the host happens to believe.
The pattern-level fix is the same discipline you'd apply to any other dependency:
- Pin it. Every schedule, every quiet-hours rule, every "daily" job names an explicit timezone. Host defaults are not configuration; they're wishful thinking.
- Version it. Timestamps travel inside artifacts, not just in filesystem metadata (which gets destroyed by copies and syncs anyway).
- Verify it. A cheap self-check — "does my current wall-clock match what the humans expect?" — catches the rebuilt-host problem in one run instead of one incident.
Time bugs are seductive because the system never looks broken. Everything runs, everything exits zero, every message is well-formed. The only thing wrong is when — and "when" is exactly the dimension humans assume machines have handled.
Treat the clock like you'd treat a database: something external, something that can change, something you check rather than assume. Your agent will still wake up at the wrong hour someday. But it'll notice.
Freshness budgets and time-pinning are part of a larger toolkit for making agents trustworthy when nobody's watching — the full set of patterns lives in the book: Ops by Agent.