My agent scheduled a daily job against a repo that didn’t exist
I asked an agent to set up a scheduled job that would keep building out my agent-log archive. Within minutes it had a recurring routine scheduled to fire every morning at 3 AM, configured to clone a repo that has never existed, and write its output into a folder format I had already looked at and rejected. The actual work it was supposed to extend was already sitting in my vault, in a shape I’d built two days earlier. The agent never read it. It built from the architecture doc instead, because when it listed the existing remote routines, the list came back empty, and it treated “empty list” as “nothing here yet, start from the spec.”
That gap, between “the list is empty” and “this doesn’t exist,” is the whole post.
The setup
I’d been working toward saving all my AI agent logs into a daily rollup. The first prompt of the session set the goal: “note we started working towards saving all my other ai agent logs. then we started a daiyl log in ben-calendar. i want to resume these thoughts … i need a scheduled remote process that scans through and does more follow up and help make the picture more clear.” The intent was clear and the agent had the right goal. A scheduled job that keeps building out the daily log.
The trap was in the name. My architecture doc described a calendar layer (I’d been calling it L4) as if it were going to be its own git repo, separate from the vault. That was the design on paper. It was never built that way. When I actually prototyped it two days earlier, I put it inside the vault at a path under the agent-system area:
with real day-files for May 5 and May 6. Those files already had a settled shape: frontmatter with session counts and active areas, a Timeline table, a Themes prose section, Items advanced, Decisions, and a time-per-area table. It was a working format I’d iterated on. The doc said one thing, the disk said another, and the disk was right because the disk was the version I’d actually used.
What the agent did
The agent took the architecture doc literally. It scheduled a remote routine on the cron expression 0 7 * * *. That’s 7 AM UTC, which is 3 AM my time. Every night, while I’m asleep and not watching, it was going to:
- Clone the phantom repo. It does not exist, so the clone fails the moment it runs.
- Write the day’s archive into a brand-new
Archive_Sweeps/<date>_sweep.mdpath inside the vault. I had never asked forArchive_Sweeps. The format I wanted already existed in the calendar index path I’d built two days earlier.
So the agent built parallel work. Not an extension of what existed, a second, divergent copy of it, on a schedule, pointed at a phantom remote, in a layout I’d rejected, running at an hour where nothing would catch it for days.
The reason it built parallel work instead of composing with mine is the part worth slowing down on. Before scheduling, it checked what remote routines already existed. The list came back empty. From “no routines exist,” it concluded “nothing has been built toward this goal,” and the only other source of truth it consulted was the architecture spec. The spec described a repo with archive sweeps. So that’s what it created.
But “no scheduled routines exist” and “no work exists” are completely different claims. The automation list was empty because I hadn’t automated anything yet. That’s the literal task it was hired to do. The work product, the day-files, lived on disk in the vault, which the agent never looked at because nothing in the routine-list told it to. It grounded on the design doc and the empty-list signal, and skipped the one place the real artifacts lived.
The catch and the recovery
I caught it because I knew the format already existed. The correction was short: we already built this. The recovery was three steps, and the first one was the urgent one:
- Pause the misfire routine before it fires. The work log entry for that session reads: “Paused misfire remote routine (was cloning a non-existent repo and writing parallel Archive_Sweeps/ instead of composing with the established calendar index format).” A scheduled job is not like a bad function call you can just not-call again. It’s armed. It will run on its own at 3 AM whether or not anyone is in the loop. Disabling it was the actual fix, everything else was cleanup.
- Read what already exists on disk and compose with it, not alongside it.
- Log the lesson so the next agent inherits it: the source priority for the rollup is Work_Log first, then session manifests, then provider indexes. Real artifacts, in that order, before any spec.
There’s a tidy footnote here. The same day I had a human-grade reviewer doing an unrelated pass over the same system, and it made the same class of mistake from the other direction. It went to clone repositories, hit incorrect or missing repo names, and self-corrected mid-run, eventually finding the real one. Both the autonomous agent and the careful reviewer started from names in a document and ran into the fact that the document’s names weren’t the ground truth. The reviewer recovered because it actually tried the clone and read the failure. The agent didn’t, because an empty list never produces a failure, it produces a confident greenfield.
The takeaways
A few things I’m keeping from this.
Agents fabricate structure from specs. Given a design doc and a live filesystem that disagree, an agent will happily build the doc. Specs describe intent. They go stale the moment you implement something differently, and you almost always implement something differently. The artifact on disk is the truth. Force the agent to read it first.
“The list is empty” is not “this doesn’t exist.” This is the specific failure mode I want to name. An empty result from a query is a statement about that query’s scope, not about the world. An empty routine list means no routines are scheduled. It says nothing about whether the work those routines would produce already exists somewhere else. Before an agent treats emptiness as a blank canvas, make it answer: empty according to which source, and is that the source where the real thing would live? Here the real thing lived in the vault, and the vault was never queried.
Recurring work earns a higher bar than a one-shot. A bad one-time action is a mistake you see and fix in the same breath. A bad scheduled action is a mistake that runs at 3 AM, unattended, repeatedly, accreting wrong output every night until someone notices. Before you let an agent schedule anything, make it ground on live artifacts and state plainly what it’s extending versus what it’s creating new. If it can’t point at the existing thing it’s composing with, it hasn’t earned the cron slot.
Composing beats inventing. A parallel Archive_Sweeps/ folder in a phantom repo isn’t just wrong, it’s worse than nothing, because now you have two divergent sources of the same record and a nightly job widening the gap. The cheap, correct move was to write into the format that already existed. Agents reach for new structure because new structure is unconstrained and easy. Extending an established shape is harder and almost always what you actually want.
The one-line rule I wrote into memory after this: before an agent schedules recurring work, it grounds on the live filesystem, not the design doc, and an empty automation list never stands in for an empty world.
Related
- Capability Gates Beat Risk Labels in Autonomous Agent Design: structural controls that prevent agents from taking unverified actions
- rtk Wasn’t Broken, It Was Unreachable: How I Found 366 Silent Failures in My AI Agent Sessions: using transcripts to catch silent agent failures after the fact
- The most valuable line in an agent’s ruleset: verify the fix in the browser before claiming it’s fixed: the verify-before-commit pattern this incident needed
- Same SHAs in Two Repos: Why Commit-Count Metrics Lie in a Clone Workflow: another case where artifact scope and actual scope diverge
- My Agent’s Chrome Was Running but Invisible: A Windows Session 0 Isolation Ghost Story: agent acts on a false assumption about the environment
- The dormant-project tripwire: a scanner that refuses to let a repo stay unclassified: forcing agents to ground on real artifacts before acting