Deploy a preset to an Agent
The Deploy to Agent workflow takes a preset you've authored on Hub and ships it across the trust boundary to a paired Agent — preset, custom types, build, flash, set-active — in one click. It's the recommended path once you have a stable wireless or USB pairing between Hub and Agent. For air-gapped or one-shot transfer, see the legacy Share a preset howto.
Prerequisites
- The Hub and the Agent are paired with TRUST level on both
sides. Anything less (
IGNORE,BLOCK,REMOVE, or unpaired) is silently filtered out of the picker — you won't see the agent at all. Promote via the Pairing menu first. - The preset you want to deploy is fully built and ready (no missing custom-type references on the Hub side). The deploy bundles every not-builtin type the preset references, so the Agent doesn't need to have authored them itself.
- The Agent is online and reachable. (Status visible from the Hub's pairing list.)
The flow
Hub side
- Open Studio → Presets on Hub.
- Right-click the preset you want to deploy → Deploy to Agent….
- The picker lists every paired+TRUSTED agent. Pick one.
- Decide whether to tick Set as active stanza set on arrival:
- Checked (default) — the Agent flashes the firmware and switches active to this preset immediately.
- Unchecked — the Agent installs the preset and builds firmware but doesn't flash; you can flash it later from the Agent UI.
- Click Deploy.
A small non-modal toast shows progress (chunk count). You can cancel mid-flight; the Agent times out and cleans up its half-buffered state within ~30 seconds.
Agent side
The Agent's user sees a permission dialog the first time a given Hub tries to deploy:
┌────────────────────────────────────────────┐
│ Deploy request │
│ │
│ Hub "<sourceName>" wants to deploy preset │
│ "<presetName>" to this Agent. │
│ │
│ This will: │
│ - install <N> custom types │
│ - replace the active firmware │
│ │
│ [ ] Always allow deploys from this Hub │
│ │
│ [Reject] [Accept] │
└────────────────────────────────────────────┘
Tick Always allow deploys from this Hub to skip the prompt for
all future deploys from the same Hub. The setting is stored in
AgentConfig.trustedDeploySources and persists across restarts.
After acceptance the Agent runs the pipeline:
- Unzip into a staging area
- Validate (preset JSON parses, manifest hash matches, custom types resolve)
- Commit (copy preset + customs into
<personality>/fixo/) - Build firmware via the same
BuildManagerthe Agent uses for local edits - Flash via
Controller::flashFirmware - If "Set as active" was ticked, switch active to the new preset
The Hub then receives a status reply (deployed_ok, build_failed,
flash_failed, custom_type_conflict, validation_failed, or
rejected) and shows it as a toast.
Why didn't my deploy land?
| Symptom on Hub | Likely cause | Fix |
|---|---|---|
| Agent not in picker | Pair-trust isn't TRUST |
Promote in Pairing menu |
BlobTransferFailed after delay |
Agent offline or unpaired mid-flight | Check Agent's connectivity, retry |
validation_failed |
Hub-side preset bundle missing customs | Make sure all referenced custom types are present on Hub before deploying |
custom_type_conflict |
Agent already has a same-named custom type with different contents | Either edit the Agent's copy to match, or delete it before re-deploying |
build_failed |
Agent's firmware compiler couldn't build the preset | Check the Agent's logs for compiler diagnostics; the preset may rely on something the Agent's board doesn't support |
flash_failed |
Serial / programming issue | Check the Agent's wiring and the board's bootloader |
rejected |
Agent's user clicked Reject in the prompt | Ask them to accept or tick "Always allow" next time |
Skipping rebuilds
If the Agent already has a preset with the exact same content hash already live, the deploy is detected as redundant — the build step is skipped and the Agent just re-confirms the active state. This keeps "deploy a fresh copy" cheap when nothing has actually changed.
Trust gate, in two places
Two separate checks gate every deploy:
- Comms-level: the Agent's
BlobCourierrejects any incoming blob whose source isn't atTrustLevel::TRUSTin the AddressBook. The blob never reaches the deploy pipeline. - Picker-level: the Hub's deploy picker filters its agent list to TRUST-only peers, so you don't see un-deployable targets in the first place.
Both gates use the same binary TrustLevel::TRUST check — there is
no "minimum trust level" knob.
See also
- Share a preset (manual export/import) — the legacy file-based transfer for air-gapped scenarios
- Pairing — how to bring a peer
to
TrustLevel::TRUST - Books and FixoLibrary — what the deploy pipeline writes into on the Agent side