I deployed a change, and the agent needed to confirm the new version was live before running a smoke test. So it wrote what agents always write in this situation:
for i in $(seq 1 40); do sleep 3; curl -s http://host/health && break; done
Then it read the output, saw the old version still serving, and declared the deploy done anyway — because the loop had exited on the first curl that returned anything, not the first one that returned the right thing. I had watched a variant of this play out a dozen times. The agent either polls too few times and gives up early, or hard-codes a sleep 120 and blocks the whole session on a fixed guess, or exits on a 200 that carries a stale body. Every time, it re-derives the same fragile loop from scratch, because there is nothing better sitting in its toolbox.
Why agents reach for sleep
An agent acts through the tools it has. Give it bash, and "wait until the server is ready" collapses into "sleep and hope," because a fixed sleep is the cheapest thing the shell offers. It has no primitive for readiness — no verb that means "keep checking this condition, on a sensible cadence, until it holds or you give up." So it fakes one, and the fake is worse in every dimension: it doesn't know how long to wait, it doesn't know what "ready" actually looks like, and when it fails it throws away everything it observed on the way down.
That last part is the real cost. A hand-rolled loop that times out tells you nothing. The agent is left to run another probe just to find out why the first forty failed — a human-speed round trip through the clipboard, which is exactly the distance I keep trying to shorten between an agent and the ground truth it can't see.
The primitive
So I wrote opencode-waitfor, a zero-dependency plugin that adds one tool, wait_for. You install it by adding one line to opencode.json:
{ "plugin": ["opencode-waitfor"] }
The tool infers what kind of target it's watching. A URL with a scheme gets polled over HTTP; a bare host:port gets a TCP connection check; anything else runs as a shell command. Three shapes of "is it up yet," one verb:
wait_for http://localhost:3000
wait_for localhost:5432 timeout 10
wait_for http://host/health expect { json_match: { status: ok, version: abc123 } }
That last one is the case that started this. After deploying commit abc123, the agent waits until /health reports that version — not any response, the correct one. The stale-body deploy I opened with simply cannot pass.
And when it does time out, it returns the last thing it saw: the final HTTP status and body, or the last command's exit code and output. The agent gets to diagnose from the failure it already has, instead of firing a fresh probe to reconstruct it.
I've written before that the job left to a human, when the agent writes more code than you can read, is standing at the boundary and shortening the distance to ground truth. Usually that's a manual act. Sometimes you can make it structural — hand the agent a primitive shaped like the thing it kept faking, and the bad behavior stops being something you prompt against and starts being something it can't easily do. A tool changes what an agent reaches for more reliably than any instruction telling it to reach for something else.
United States
NORTH AMERICA
Related News
OpenAI's CEO of AGI Deployment, Fidji Simo, Is Stepping Down
15h ago

Another Day, Another Game Boy-Style Handheld I Don’t Need but Can’t Resist
15h ago

NASA finally releases a critical planning document for private space stations
15h ago

Hiboy P6 Fat Tire Electric Bike Review: Smooth Sailing
15h ago

An Agent That Hunts Bugs in My App While I Sleep
10h ago