Verified against the installed ZCode desktop bundle and a live Remote Control session on 2026-09-08.
workspace-list-responsereturns the real desktop workspace and task inventory.zcode-task/getTaskConfigOptions({ taskId })returns model options independently of the conversation snapshot. Use it for discovery and switch verification becausegetTaskSnapshotcan reject tasks whose saved model is no longer available.- If the target's saved model prevents even that call, another unarchived task in the same workspace can supply the currently advertised options. The target model is reported as unavailable/unknown until
setConfigOptionsucceeds and target-local verification passes. setConfigOptionrejects inactive sessions. For that exact error,resumeTaskcan load the existing task with an explicitly selected advertised model and thought level; it does not send a prompt. ZCode Ops then requires target-local option verification before reporting success.zcode-task/getTaskSnapshotwithclientMode: "web-remote-replayable"normally callsresolveTaskIndexResumeHintsbefore reading, which can reapply an unavailable historical model even after a successful runtime switch. PassingresumeModelPolicy: "ui-resolved-only"skips that index-hint step. Live verification on 2026-09-08 recovered the requested task's user prompt and assistant progress through the remote API, without a model change or prompt side effect.- The installed desktop
zcode-taskservice implementsgetTaskConfigOptions,setConfigOption, andsetModel. Its model branch accepts{ taskId, traceId, configId, value }, routesconfigId: "model"to the runtime model switch, and returns refreshed config options. - Live model options observed:
GLM-5.3-Flash,GLM-5.3,deepseek-v4-flash,deepseek-v4-pro,deepseek-v4-flash-vision-exp, andglm-5.3-flashthrough the user's enabled providers. setConfigOptionis allowed only after matching a freshly advertised option (target first, with the same-workspace recovery described above). ZCode Ops refuses model changes while the task reportsrunning, then calls target-localgetTaskConfigOptionsto verify the new model.- Older tasks can be slow enough for their direct
workspace-bridge-opento be superseded. Because the bridge is workspace-scoped, ZCode Ops may attach another live task in the same workspace and still address the requested task id; it never substitutes the target task itself. zcode-task/stopGeneration({ taskId, workspacePath, workspaceIdentity? })sends a native V4 conversationstopcommand. It is task-scoped, not conditional on an expected run ID. ZCode Ops rechecks native running status immediately before this call; ACK is reported only ascancel_requested. Fake-transport and tool regressions cover targeting, ended turns and uncertain delivery; no live business task was stopped for validation.zcode_remote_waitpolls native workspace-list status with a bounded 0–30 second wait window plus request latency. The cursor includes task/workspace/native status/archive state, excluding timestamps and text. Connections are released between polls. Live verification returnedrunningwithtimedOut: true, without inferring interruption; deterministic tests cover transitions, attention, missing tasks and transport failure.- The remote adapter allowlists only
getTaskSnapshot,getTaskConfigOptions,resumeTask,sendPrompt,setConfigOption, andstopGeneration; task creation and arbitrary service dispatch remain blocked. - Sharing links are stored without format probing. URL parsing and required authentication fields are checked only when a remote operation is attempted. A connection failure asks for a new link; no automatic send retry occurs.
- Codex startup performs no ZCode operation and shows no link prompt. OpenAI's optional plugin components currently run through the ChatGPT MCP Apps UI path, so this local Codex plugin uses the native conversation input instead of a separate imitation window: https://developers.openai.com/plugins/build/chatgpt-ui.
The installed desktop bundle out/host/index.js routes sendPrompt through
sendPromptToAgent to V4 sendText with heldQueueDisposition: keepQueueAndSend.
The installed resources/glm/zcode.cjs implements sendText / startPromptTurn
using native app.sendInput; it checks model readiness and input admission.
There is no facade requirement to rewrite a previous error to idle first.
The queue's old idle/completed allowlist prevented this native path from being
called. Queued authorized prompts now also admit failed, while rechecking the
target and retaining the existing pending-input, FIFO and uncertain-send guards.
resumeTask remains session loading/model recovery, not proof that a new turn ran.
Invalid remote frame on long conversations was a receiver-limit bug, not evidence
of an expired Sharing Link. A live response declared 2,395,800 bytes in four
fragments; its first base64 fragment was 1,048,236 characters (786,177 decoded
bytes). The receiver incorrectly treated our outgoing 512 KiB fragment size as
the peer's receive limit. Reading two messages succeeded with the same link.
The receiver now accepts base64 fragments up to 1 MiB (768 KiB decoded), while the physical JSON envelope still must fit 1 MiB. The 16 MiB assembled-message cap, fragment-count/in-flight limits, canonical base64, size and CRC32 checks remain enforced. Outgoing fragmentation stays at 512 KiB. Synthetic regression coverage reproduces the observed four-fragment shape through receive/decode, including reversed arrival order, acknowledgment and oversize rejection.
Live default-limit reads subsequently recovered 100 messages from task 1 and 21 messages from task 3. Task 1's text output was capped at 24,000 characters; successful transport does not imply complete history or review acceptance.
Operational lessons: match exact task IDs (titles 1 and 01 are distinct);
inspect all monitored tasks each pass; serialize only short remote calls, never
wait for one task's completion before checking others. Native completed means
a turn ended, not that the overall task or review passed. Check messages and
authoritative evidence before advancing. Never retry an uncertain send/stop;
inspect delivery first. Diagnose transport fields before requesting a new link,
and never record link secrets or conversation bodies in diagnostics.
The previous eight-task review monitor was retired at the user's request. Its two-round review gate is no longer a prerequisite for the Bio-Harness handoff.
Installed out/host/index.js implements limitTaskSnapshotMessages as a tail slice,
with history.truncatedBefore and totalMessages. No snapshot before/after-history
parameter was found in that implementation. Live snapshots include message id,
role, content, and turnIndex; some initial assistant records precede a user
record with the same turn index, so turn index alone is not enough for correlation.
zcode_remote_read now pages forward within the returned window, using an opaque,
stateless checkpoint containing a target digest, native message ID, consumed UTF-16
offset, content-prefix digest and native status/pending-count fingerprint. It has
no transcript cache or background process. A cursor continues across separate MCP
gateway processes. The last consumed message can grow or be replaced; an absent
anchor produces historyGap without advancing it. Edits before that anchor are
outside this tail-continuation contract. hasMore covers the plugin's output cap,
not unavailable native history; tailCursor is an explicit skip-to-current-end.
zcode_remote_wait(mode: "messages") requires a message cursor and returns new
content, state/pending-count changes, a history gap, or timeout. Unchanged old
completed state alone does not wake this mode as a new reply. Default status
mode remains available with its distinct status cursor. Both release connections
between polls, with the wait window plus native request latency determining total
duration. Missing tasks or transport failures propagate errors, not completion.
zcode_remote_send captures a baseline before sending; a failed baseline prevents
the send. ACK returns the baseline cursor and the existing trace/query/message IDs.
requestMessageId correlation requires the exact user ID and subsequent assistant
records with the same native turn index, before the next user message. If the
runtime rewrites that ID or the user record falls out of the window, correlation
stays unconfirmed. Correlation is snapshot evidence, not proof of final delivery
of all paginated text, task completion, or business acceptance. No injected receipt
prompt, model inspection, or automatic retry is needed for continuation.
Live MCP verification on 2026-09-09 read 46,481 characters across 12 pages from
sess_66299dd9-bd22-49a4-8b0a-2e5f5d36be04, spawning a separate gateway for each
call. At the end hasMore=false, another read returned zero messages, and message
wait returned timeout with unchanged native completed status. The cursor was
275 characters. No Sharing Link or conversation bodies were persisted for this check.
One no-tool/no-file-change prompt was sent to the existing plugin-review task
sess_364f3d09-4b3d-4db4-811f-3624dde5a68f. The first wait returned its native user
message and an empty assistant record while running; the next returned the growing
assistant body ZCODE_RETURN_OK_20260909 with native completed. The native user
ID was newly generated, not the supplied send message ID. Therefore correlation
correctly remained unconfirmed; assistantTextReturned separately reports actual
assistant text returned in a page. Exact request-ID correlation is supported by the
adapter contract and deterministic checks, but NOT verified available in this
desktop path. This is a native limitation, not a reason to resend the prompt.
The relay authenticates a Sharing Link as one mobile terminal. Opening multiple
WebSockets with the same link causes the relay to return KICKED; removing the
old global lock and creating one connection per read is therefore invalid.
The adapter keeps at most one physical connection and exposes zcode_remote_read_many
and zcode_remote_wait_many for multi-task monitoring. It groups tasks by
workspace, opens one bridge per group, and runs that group's getTaskSnapshot
RPCs concurrently through independent request IDs. Groups for different
workspaces are switched sequentially because the installed desktop runtime
keeps one currentBridge per remote-control window. A second bridge open on
the same connection stalled a subsequent snapshot in live testing; resetting
the outgoing frame sequence did not resolve it and was reverted. Close and
reconnect between workspace groups. Two live tasks in different workspaces
returned in 4.9 seconds with no missing targets or errors.
Single-task calls remain serialized by the connection guard. The batch tools are the supported concurrency boundary; they do not create a second terminal, change task write ordering, or provide event push. Direct read/wait still requires a caller. The explicit background queue worker now polls independently without LLM turns; this is not a Codex wakeup channel. Queue details and limits are in message-queue.md.
Batch calls accept at most 8 task IDs, run at most 4 snapshot RPCs concurrently per workspace, and default to 3000 returned characters per task. Failed targets have separate errors without discarding successful pages; all pending calls settle before switching or closing a bridge.
The desktop bundle is implementation evidence, not a stable public contract. Re-run the live snapshot and switch verification after ZCode upgrades.
A reported queue head stayed acknowledged / native running after the desktop
turn completed. Its marker, native user ID and turn index were already matched;
only the first 64 characters of its eventual 953-character reply had been collected.
A single-target read from that same saved cursor returned the remaining 889
characters and completionConfirmed: true. This ruled out a missing model reply
or an incorrect team label for this incident.
The seven-target worker read reproduced a shared-bridge stall: several initial snapshots arrived, then another snapshot and the healthy tasks' confirmation snapshots timed out. Only one task returned a usable page. The precise desktop condition that stalls the RPC remains unconfirmed; the integration bug was allowing that shared failure to repeatedly prevent healthy task completion reconciliation.
readMany now retries failed batch snapshots once per task on fresh, isolated
connections, with the original cursor and unchanged completion guards. Successful
pages are not replayed. The fallback performs reads only, never prompt sends or
model changes, and a failed isolated read remains an explicit per-task error.
Live verification recovered six of the seven pages (one task still reported
workspace_unavailable) in about 106 seconds. The incident's original queue head
advanced to completed through MessageQueue.observe; no prompt was resent and
no queued follow-up was dispatched during verification. This validates the reported
head's recovery, not every native task's health or a maximum model concurrency.
The deterministic regression reproduces shared-connection poisoning and verifies
healthy completion, same-task follow-up admission, and no replay of old requests.