python -m pip install --upgrade truffile.
Normal deploy uploads the original bundle to firmware’s native installer.
Firmware uses its existing builder containers to run the install plan. The CLI
handles progress, uploads, setup forms, and browser authorization. It does not
reimplement connection isolation or rewrite the manifest into a legacy plan.
deploy accepts a directory containing truffile.yaml or a .truffle ZIP.
For a directory, files are packaged with stable ordering/timestamps. .git,
virtual environments, Python caches, .env/.env.*, and existing .truffle
archives are excluded. .truffleignore supports relative glob patterns and
directory prefixes, one per line. Symlinks, escaping archive paths and duplicate
archive entries are rejected. Bundles are limited to 200 MiB expanded.
validate and deploy --dry-run perform local bundle preflight. The manifest
is passed through unchanged: firmware performs full schema and install-plan
validation, including connection scopes, connectors, static resources, base
image, and resource profile. A preflight pass is not proof that a particular
firmware supports every declared feature.
Install, update, replace
Both update and replacement require the PyFW developer-upload capability
available on current firmware. The CLI checks support
using a read-only request before starting either mutation. Older firmware
gets an upgrade-required error. It never falls back to deleting the app or to
a catalog reset. The server retains its existing behavior for older clients.
Successful CLI deployment verifies the installed bundle hash after completion.
Keep the same
metadata.bundle_id when updating an installed app.
The direct builder remains available for development/debugging:
--interactive opens the legacy builder shell. Normal native deployment already
prompts for account setup; it does not need that flag. Direct builder deployment
supports the older schema and fresh bundle IDs only. Use normal deployment for
modern manifests, updates and replacements.
Accounts and permissions
Friendly app names, bundle IDs and UUIDs are accepted. Account aliases and UUIDs are accepted too. If a name is ambiguous, the terminal shows matching choices.Work; the permission
example chooses an account and makes it read-only. To select directly:
--yes is provided. Scripts must provide
an unambiguous account and --yes for deletion. --json and --non-interactive
never open a picker or prompt. No selection silently means “all accounts.”
Permission modes are default, read-only, read-write, and auto-review.
default removes the account override so device policy applies. Omitted
--notes preserves the current review notes. These commands do not alter
device-wide defaults or grant an app permission automatically.
Authentication
Native text/password forms, including API-key setup, are rendered in the terminal. Password inputs are hidden. For automation, supply a JSON map of field names to string values:name or step_index.name
when separate steps use the same field name. Supplied values are not printed.
For OAuth, the CLI shows the authorization URL and accepts a callback URL or
provider approval code. URL callbacks must match the pending state. On POSIX,
firmware-provided localhost callbacks can complete automatically; pasting is
also available when the browser is on another computer or the port is busy.
Browser/VNC setup cards show the device setup URL and follow the card’s completion
behavior. Native device-code approval displays the link and waits for the
provider process to finish without asking for a callback paste.
Provider-specific consent, token refresh and custom setup still run
through the firmware install plan, not through a new CLI token store.
Interactive authorization is not silently completed in JSON/noninteractive
mode. Missing input returns an interaction-required error and requests
cancellation. Rerun interactively or supply form answers as appropriate.
--timeout defaults to 900 seconds for install/add/reconnect. A timeout or
disconnect is not permission to retry blindly: cancellation is requested, but
the operation may already have committed. Inspect the app before retrying.
The device can expire sign-in before the CLI’s deadline; increasing --timeout
does not extend that authorization window. The CLI continues receiving device
responses while prompting, closes stale prompts/callback listeners on expiry or
disconnect, and reports the device’s error. An expired setup needs a new sign-in
link.
Mutations are serialized on firmware, so an immediate follow-up command can
report that another operation is still finishing.