The readiness envelope
Some handlers cannot complete on the first call: an editor screenshot needs a rendered frame, a property monitor needs the probe's next sample batch, a full-Control UI scan takes a frame or two. The naive design — the handler blocks until the data exists — stalls the bridge, blocks the editor's main thread, or times out with a generic error pointing at the wrong layer.
Instead, poll-and-cache handlers always answer within one round-trip:
// not yet — and here is why
{ "ready": false, "pending": true, "reason": "capture_pending" }
// ready
{ "ready": true, "samples": [...] }The token table
| Token | Handler | Meaning |
|---|---|---|
recording_pending | godot_input_stop_recording | the stop push hasn't landed from the probe yet |
capture_pending | godot_runtime_get_property_samples, game-frame capture | the request is dispatched; the probe answers on a later frame |
read_pending | godot_runtime_read_property | the one-shot read is dispatched; the probe replies on a later frame (#571) |
output_pending | godot_runtime_get_game_output (cold start) | the first probe pull is in flight; the ring is empty until it lands |
scan_in_flight | godot_runtime_find_ui_elements | the full-Control scan runs over the next frames |
probe_pending | godot_profiling_get_performance_monitors | the probe hasn't answered the first monitor pull |
rescan_in_flight | godot_asset_import_get_status | the editor's filesystem scan is running; the status read is provisional |
editor_not_drawing | godot_editor_capture_screenshot | the editor hasn't rendered a frame yet (e.g. minimized/unfocused) |
godot_asset_import_get_status also reports scanning: bool — the same EditorFileSystem.is_scanning() read the parse-check gate keys on, so an agent can distinguish "not imported yet" from "the scan hasn't flushed".
poll_ready and the no-silent-stall rule
The server-side loop is poll_ready(bridge, command, params, timeout_ms):
- Make at least one attempt (a fast tool never returns a pending answer).
- Poll on a fixed cadence until the result is
readyor the deadline hits. - On expiry: if the last result carried a
reason, the tool raises aTIMEOUTerror relaying it — the agent seesTIMEOUT: … did not become ready within 2000ms (last reason: capture_pending)and can act on the cause instead of guessing.
The design rule: no bridge call can stall silently, and every ready: false beyond a grace period names its cause. A handler that can't complete should never hang the transport; the addon is the only layer that knows why Godot isn't cooperating, so it says so.
Grace periods
Not every first-poll miss is a failure — captures legitimately defer by a frame. So the pattern is:
- Captures (screenshots, frames): 2 polls (one frame deferral + slack).
- Probe-based polls: the standard poll cadence (
DEFAULT_POLL_INTERVAL_SECONDS), bounded by the tool'stimeout_ms.
A handler may defer normally (one empty ready: false); only a still-pending handler past its grace window carries the token. In practice every handler listed above emits the token on every non-progress poll — simpler to reason about, and poll_ready's deadline is the real bound.
Why agents care
Without the token, a pending poll and a broken probe are indistinguishable — the agent burns its retry budget on a capture that will never land, or gives up on one that needs one more frame. With it:
recording_pending→ the game is still flushing the input buffer; wait, or checkinput_get_stats.read_pending→ the one-shot read is in flight; poll once more (#571).output_pending→ the first output pull hasn't landed; poll once more.scan_in_flight→ the UI scan is running; poll once more.probe_pending→ the probe autoload is present but slow; checkruntime_is_playing.rescan_in_flight→ the import is progressing; keep polling rather than re-importing.editor_not_drawing→ the editor isn't producing frames (unfocused window); focus the editor or wait for the next frame.