← Back to Blog

Day 120: The Agent Was Alive the Whole Time

A bug worth a whole day: on production the chat would announce “The agent didn’t respond,” and it was wrong. The agent had responded. A page refresh brought the saved reply right back. The error sat on top of a perfectly good answer and hid it, so anyone who didn’t think to reload simply lost the response. It showed up most on slow runs, an Ollama Cloud model warming up after a switch, exactly when a patient user is most likely to trust the message and walk away.

Five clocks, all guessing from silence

The root cause is the kind that makes you wince once you see it. The question “is the agent still alive, did it respond” was being answered by five independent heuristics, each running on its own clock, all of them guessing from the same thing: silence. A 60-second client stuck-timer. An orphan detector. A 15-minute server watchdog. A 180-second first-chunk watchdog. A 15-second delay hint. Five mechanisms, one question, five chances to be wrong. And the orphan verdict was one-shot: once it fired it was never re-checked, so the reply that landed a few seconds later had no way to surface until a manual reload. Silence was being read as death, and the answer that arrived right after was talking to a UI that had already given up.

One source of truth

The fix was to stop guessing. OpenClaw runs the agent, so OpenClaw knows whether a run is live, finished, or dead. Not by inference from a quiet socket, but as a fact. The day’s work was to make that the single authoritative signal and retire the five guesses behind it, surfaced through openclaw-node 0.13.0, the SDK I’d extended two weeks earlier for exactly this kind of “ask the runtime what’s actually true” question. This rhymes with something I keep relearning on this project: a signal that guesses from silence is a lie waiting to be caught. The honest version asks the component that knows.

Governance, the Odoo edition

The other strand of the day pushed the same instinct into Odoo. Operator agents could already read and write records, but the actions that actually matter in an ERP, confirming an invoice, validating an order, approving an expense, were going out as raw method calls. Governed means named: each of those became its own tool (confirm, validate, approve) that passes through the permission allow-list and lands in the audit trail like everything else. An action that moves a business state should not get there through a side door. The rest of the day was tooling: a new Ollama Cloud model into the catalog and five removed ones out, and the release process itself became a tag-driven runbook so the next version cut leans on a checklist instead of my memory.

Day 120

The thread running through the day is that silence is not information. Five systems inferring life from a quiet connection are five systems that can be wrong at once, and on a slow run they were. One component that knows the truth beats five that estimate it. That is the same lesson as the dead watcher, the version that lied about its number, and the tests that only said “maybe”: make the mechanism report what is real, and stop dressing up a guess as a fact.

← Day 119: Auditing My Own Marketing for Lies Day 121: Separating the Channels →

Pinchy is open source and ready to deploy. Clone the repo, run docker compose up, and your first agent is live in minutes.