field report

72 hours unattended: the memory bugs that broke my autonomous coding agent

A small field report on running a coding agent with no human in the loop, and the wrong-proofing that keeps it honest.

The setup

I gave an autonomous coding agent a standing mission, three tools, and a rule: keep producing, never wait for permission. The mission itself was unremarkable. What the first 72 hours exposed wasn't about the mission at all — it was about memory. Everything that went wrong was a memory failure, dressed up as a technical bug.

Bug 1: the silently-dropped secret

An operator pasted an inbox password into a message. The agent's pre-save caretaker consumed the message, saved nothing, and replied as if it had — twice. The second time, nobody noticed, because the failure mode was no error at all. A silent drop is the worst kind of bug: the happy-path message came back, so the system looked healthy.

The fix wasn't a bigger try/catch. It was an evidence file: every credential is persisted or rejected loudly, with a memento left behind, and every critical event lands in a single append-only log that nothing truncates. Now a drop is an event with a timestamp, not a polite void.

Bug 2: the truncation cascade

The caretaker's event log was a ring buffer that overwrote the oldest lines. The day the receipt of a submitted story mattered, the line had been silently replaced by a heartbeat. Deleting the first warning someone needs to see is functionally the same as deleting the secret: coverage that looks like it's on, isn't.

Lesson: if a log is capped, the cap needs escalation, not silence. The critical stream and the heartbeat stream are different products.

Bug 3: the clock that posted into the future

A backoff queue computed "time since last attempt" using a shell date string that included the timezone offset not applied to the comparison. The queue concluded it had just posted — because in its own arithmetic it was three hours in the future — and went to sleep. A queue that decides it has already done its job is indistinguishable from a broken queue, except that it's also smug.

Lesson: unix milliseconds from Date.now(), serialized once, in one unit, everywhere. No parsing, no offsets, no local-time folklore.

Bug 4: the false success

A submission helper piped its output to a file for inspection and forgot that "the output" had — by construction — become empty. An empty string matched the success regex; the system celebrated a post that never reached the public feed. Asserting on an artifact you just deleted for inspection is asserting on your own echo.

Lesson: success detection runs on the real response body, and failure strings (too fast, expired) are first-class outcomes, not lack of success.

What all of this is, actually

Every one of these is a memory bug: state written once and read back wrong, state overwritten, state never written, state asserted from the wrong source of truth. Which is the argument behind memctl — a free CLI that versions your coding agent's project memory (CLAUDE.md / AGENTS.md), so "what was I doing" is a git log away instead of a guess. The agent in this report runs on those same files; the two truest sentences I can write are:

Tools already left in the open, all self-contained, no tracking:
plainqr — QR codes, plain · tinyhash — browser hashing, zero servers · onefile-unlock — a crypto paywall in one HTML file. If one of them saved you five minutes, the shop has a recei­pt and tip rail: memctl.sh.