Fleet Updates¶
Update Embody on Convoy nodes without touching each machine -- and without
granting Allow Execute TD Python anywhere. update_embody is a bounded,
registered Convoy operation: the node's own updater fetches the official
GitHub release, verifies the sha256-pinned manifest, refuses downgrades and
TD-build-floor violations, and swaps the component in place. No caller code
or URL crosses the wire.
The two-call flow¶
convoy_list_nodes -> who is below latest
convoy_update_embody(node="render-3") -> durable update job on that node
or the whole fleet at once:
Each dispatch returns a per-node delivery_id; poll with
convoy_get_job(delivery_id=...). A finished job carries
version_before / version_after; a node already at the latest release
finishes done with the versions equal. A successful install restarts the
node's MCP server, so its next call may ride one reconnect blip.
Nodes are skipped (and named in skipped) when they are offline, disabled,
or in Perform Mode -- never update a machine mid-show.
Requirements and caveats¶
- The target must run Embody >= 6.0.257. Older nodes do not serve the
update_embodyoperation and refuse it as unknown -- they need one manual update first (or the update via TD Python where that is already granted). - The node needs GitHub reachability. The updater fetches
releases/latestand the release assets itself; an offline show LAN reports a network error in the job record instead of updating. update_embodynever needs the TD Python grant. It is classifiedexecutes_arbitrary_code=Falsein the Convoy operation registry, and it is deliberately the remote-exposed one of the fleet verbs --run_testscounts as arbitrary code, andsave_projectis local-only.- Persistence: the updater installs into the live component. If your
project embeds Embody inside a
.toxyou manage yourself, re-save that component (or the project) after the update, or the machine reverts on its next open. Saving is a local step --save_projectis deliberately not remote-exposed -- so save from a session on that machine, or useconvoy_restart_nodewith itssave_then_restartpolicy.
Traps (learned in the field)¶
- The Embody Update pulse is not the self-updater -- it re-exports
externalizations. The self-update entry is
Checkforupdate/UpdaterExt.CheckForUpdate. - A dev checkout refuses the update (the updater protects a source checkout); the refusal lands in the job record instead of a swap.
- A second
update_embodywhile one is already in flight reconciles to the existing job handle -- poll that job, don't expect a new one. - A disabled local node never appears in
convoy_list_nodes(the host filters it before the bridge sees it), so it reads as missing from the list, not asskipped. CheckForUpdate(interactive=True)(the parameter pulse's default) raises a blocking modal -- on an unattended machine use theupdate_embodyoperation, which always runsinteractive=False, auto_install=True.- Version metadata is already in
convoy_list_nodes(embody_versionper node) -- neverget_opthe Embody COMP for it (a ~230-parameter read). For anything else,get_parameterwith a search pattern. - Local nodes in
convoy_list_nodescarry acapabilitiesfield (td_python,full_shell). Remote nodes deliberately do not -- capability grants are never advertised across the LAN -- so absence means unknown, never allowed.