The loop we bought it for had never run
- debugging
- agents
- harness
- observability
We chose this agent framework for one feature above all others: it can write its own skills. It notices it did something awkward, reflects at the end of a turn, and saves a better way to do it next time. That self-authoring loop is the reason it is the thing we ship rather than something we wrote ourselves.
In our fork, it had never run. Not once, in weeks.
The differential that made it findable
Credit where it is owed: this was found because the operator had watched the stock version do it, on the same Mac, that same week. That is the whole diagnostic. Two installs, one machine:
stock harness, off-the-shelf provider -> authors skills
our fork, our model, our memory plugin -> never has
One machine, one afternoon, one difference in behaviour. Everything about the hardware, the OS and the user is held constant for free. If you have that, you have a bisect; without it we would still be reading our own code and finding nothing wrong with it, because there is nothing wrong with it.
Root cause
The end-of-turn review runs on a daemon thread. Daemon threads do not keep a process alive — when the main thread finishes, they are killed wherever they happen to be standing.
Every unattended entry point tears the agent down the instant the turn returns. The scheduled path closes the agent immediately after the call. The one-shot path exits at the first print. Both of them arrive while the review thread is mid-model-call, and the kill is not an exception — the thread simply stops existing. It never reaches its own error handler, so nothing is logged and no artifact appears.
The trace is the same every run:
spawned -> thread entered -> model called -> thread GONE
A fault-handler dump confirmed it from the other side: nine live threads at the moment of teardown, and the review thread not among them.
For completeness, the thread handle was discarded at construction, so even a caller who wanted to wait for the review had no way to.
Interactive sessions survive this entirely by accident. The process keeps living because a human is still sitting there, so the thread gets to finish. That accident is the only difference between the stock experience and ours.
Why weeks went by
Because success and failure emit the same thing: nothing.
Upstream logs nothing when a review succeeds, and warns into a void when it fails. So declined to save, gated out by the quality bar, and killed mid-flight are one symptom — no new skill — with three completely different causes and no way to tell them apart.
There was a column in the database that looked like evidence. It reads zero even on a successful review, because the review agent runs with persistence switched off, so its tool calls are never recorded. It was never evidence of anything. It cost hours before that was established.
What changed
The teardown paths now wait for the review instead of racing it, and the loop reports on itself — spawned, entered, completed, declined, failed — so the three indistinguishable failures are now three distinguishable lines. There is a telemetry entry point you can run against a live install to ask, plainly, whether the thing has ever worked.
The generalisable version, which we have now paid for twice: an unattended path is a different program from an interactive one. Anything backgrounded, deferred to end-of-turn, or handed to a daemon thread is running on borrowed time that only a human's presence was extending. Test the unattended path, or you have tested nothing about how the product actually runs at a customer site — which is where every path is unattended.