trust-runtime¶
trust-runtime is the main operator/runtime CLI for truST. Developer and
automation workbench commands are moving to trust-dev; deprecated
trust-runtime aliases remain during the migration window and will not be
removed before 2026-10-05. Removing them requires a separate behavior-change
release note.

Figure: The top-level trust-runtime command families as the binary reported
them before new was added; the table below lists new.
Top-level Command Families¶
| Command | Purpose |
|---|---|
run / play |
start a runtime instance |
ui |
interactive terminal UI |
ctl |
send control requests to a running runtime |
new |
create a project folder with the files a new project starts from |
identify |
make a runtime show where it is by blinking its identify output |
check |
validate sources/config without writing a program image |
build |
compile the project into the program image program.tpi |
validate |
validate project config + program image |
hmi check |
check the project's HMI files against its program, for CI |
hmi test |
compare every HMI page's look with its approved screenshot, for CI |
hmi-password |
print the stored hash of an HMI user's password |
test |
deprecated alias for trust-dev test |
docs |
deprecated alias for trust-dev docs |
ads |
Beckhoff ADS onboarding backend, symbol import, route artifacts, and validation |
comm |
offline communication schema, configuration, discovery, topology, and symbol browsing |
plcopen |
PLCopen import/export/profile |
registry |
package registry workflows |
setup |
initialize system I/O config |
ide |
serve the browser IDE |
agent |
deprecated alias for trust-dev agent serve |
commit |
deprecated alias for trust-dev commit |
wizard |
create a new project folder |
deploy / rollback |
versioned deployment and rollback |
bench |
communication/runtime benchmark surfaces |
conformance |
deterministic conformance suite runner |
toolchain |
the compiler toolchain that builds programs: status, install, bundle |
firmware |
install truST's firmware on a chip through the chip's own boot loader: install |
Entry-point and Error Contract¶
The top-level parser accepts --verbose before or after a subcommand. When a
subcommand is not recognized, the CLI computes a bounded edit-distance
suggestion against every shipped top-level command, ignoring global flags when
identifying the mistyped command. Suggestions are emitted only when the best
command is at most two single-character edits away; distant inputs receive the
normal usage error without an invented recommendation.
Errors returned to the top-level entrypoint exit with status 1 outside --ci
mode after printing the stable Error: prefix and any applicable configuration
tip. Commands with a documented machine contract, including check, may exit
directly with their stable command-specific status. In --ci mode, returned
errors use the documented command-aware CI exit classes for configuration,
build, test, timeout, and internal failures.
Common Commands¶
New¶
Usage: trust-runtime new --parent <FOLDER> --name <NAME> [--force] [--json]
new creates the project folder <FOLDER>/<NAME> with the files that a new
truST project starts from: src/Main.st, src/config.st, trust-lsp.toml,
runtime.toml, io.toml, .vscode/launch.json, .vscode/settings.json and
.gitignore. The runtime.toml names no control endpoint, so the runtime uses
the platform default, and .gitignore lists /.trust-runtime/, the folder that
holds the endpoint file.
The name is trimmed and must be one plain folder name on every platform. It must
not be empty or . or .., and must not contain /, \, a drive prefix or
another character that Windows refuses (: * ? " < > | and control characters).
It must not end with a dot, and must not be a device name that Windows reserves
(CON, PRN, AUX, NUL, COM1 to COM9, LPT1 to LPT9, with or without an
extension). An existing folder that is not empty is refused unless --force is
given. With --force, the scaffold files are overwritten and every other file in
the folder is kept. An existing .gitignore is always kept; it only gains the
/.trust-runtime/ line when no line ignores that folder yet.
With --json, success prints
{"project":"<absolute folder>","focus":"<absolute folder>/src/Main.st"}. A
refused or failed request prints {"error":{"code":"<code>","message":"<text>"}}
and exits 1. The codes are:
| Code | Meaning |
|---|---|
name |
the name is not one plain folder name on every platform (see above) |
exists |
the folder exists, is not empty, and --force is not given |
not-directory |
the folder, or its parent, exists and is not a folder |
io |
a folder or file could not be read or written |
Without --json, success prints Created project <absolute folder>. A failure
prints the message with the Error: prefix and exits 1.
Check¶
Usage: trust-runtime check [OPTIONS]
check validates required runtime.toml and io.toml, optional ads.toml
and opcua_client.toml, the source/dependency layout, and compilation without
writing a program image. It runs the build's checks and code generation for
this computer's CPU and needs no compiler toolchain. It aggregates independent
configuration and compile issues in one response instead of stopping at the
first failure.
--json and --ci emit response version 1 with ok, status, issue counts,
stable issue codes, and source/dependency lists. Configuration or source-layout
errors exit 10; compile errors exit 11. A successful check exits 0 and never
writes a program image.
When runtime.toml sets [runtime.identify] output, check also makes the
load check of run on the program the sources compile to: a program that uses
the identify output is the issue config.identify (exit 10), with the same text
run prints.
Build¶
Usage: trust-runtime build [OPTIONS]
Primary options:
--project--sources--ci--target--emit-source
The default source root is <project>/src; relative --sources values are
resolved from the project. A successful build writes the program image
program.tpi and its deployment record deployment-record.bin into the
project, and its report to build/build.json. --target builds for a device
(esp32c6, stm32u5a9), a CPU (x86_64, aarch64, riscv32imac,
thumbv8m) or a Rust target triple instead, and writes
build/program.<triple>.tpi and build/deployment-record.<triple>.bin;
--emit-source keeps the generated Rust crate in the build folder. The first
build that needs the compiler toolchain installs it. A failed source,
dependency, or compile step preserves any existing artifact. --ci prints the
build report: response version 1 with the target, whether the image is a debug
image, the image and record paths, the image's size, the signing key, and the
memory figure; build failures exit 11.
Validate¶
Usage: trust-runtime validate [OPTIONS] --project <PROJECT>
Primary options:
--project--ci
validate makes the same checks as run makes when it loads the project, so a
project it accepts is a project run accepts. That includes the identify load
check: with [runtime.identify] output set, a program that uses the output, an
io.toml that maps the GPIO line, or an output beyond the output image is
refused with the error run prints.
HMI check¶
Usage: trust-runtime hmi check [--project <dir>] [--json]
Runs the HMI Builder's checks over every HMI file of the project, for its own CI: the files
load, the assets the pages use are there, every binding resolves in the program with a
compatible type and direction, and every control is within the write policy of
runtime.toml. It compiles the program with its libraries first. Each problem prints as
file:line: message; any problem exits 1, a clean project exits 0 with
HMI check passed: N files. --json prints { "ok", "problems": [{ "file", "line",
"message" }] }.
HMI test¶
Usage: trust-runtime hmi test [--project <dir>] [--update] [--chromium <path>]
Draws every HMI page in headless Chromium as the runtime display lays it out at the screen's
design size, with design samples in place of live values, and compares it with its approved
screenshot hmi/screens/<page>.png. A page whose look changed, or that has no approved
screenshot, fails the command (exit 1) and leaves its new look as
hmi/screens/<page>.actual.png to review; --update approves every page's new look. Chromium
is taken from --chromium, CHROMIUM, the usual names on the path, or Playwright's cache.
Test¶
Usage: trust-runtime test [OPTIONS]
This forwards to trust-dev test and prints a deprecation warning with the
2026-10-05 removal-not-before date.
Primary options:
--project--filter--list--timeout--output--ci
Docs¶
Usage: trust-runtime docs [OPTIONS]
This forwards to trust-dev docs and prints a deprecation warning with the
2026-10-05 removal-not-before date.
Primary options:
--project--out-dir--format
Agent¶
Usage: trust-runtime agent [OPTIONS] <COMMAND>
Compatibility subcommand:
serve
This forwards to trust-dev agent serve and prints a deprecation warning with
the 2026-10-05 removal-not-before date.
Communication¶
Usage: trust-runtime comm <COMMAND>
comm operates through the same communication configuration and inspection
contracts used by the IDE without requiring a running PLC runtime. Successful
responses are JSON objects with a command-specific schema_version; --json
is accepted on every subcommand for explicit machine-readable invocation.
Subcommands:
schemareturns the available protocol configuration schema and can filter it with--protocol.applyvalidates--paramsas a JSON object and appliesadd,edit,upsert,remove,disable, orvalidateto project configuration files.topologyprojects configured hosts, runtimes, endpoints, and links from project files. Configured state is not reported as live connectivity.discoverperforms host-local, connect/read-only discovery. Candidate confidence distinguishes protocol proof from a likely endpoint or mere TCP reachability; write probes are not supported.browse-symbolsreads a configured project, target, or cached ADS snapshot and returns the canonical tree/import response.opcua-trust list|clearinspects or clears the selected OPC UA client trust store.
Malformed --params, unreadable or invalid snapshot files, unknown protocols,
and configuration validation failures are returned through the normal
top-level error contract.
Commit¶
Usage: trust-runtime commit [OPTIONS]
This preserves --project, --message, and --dry-run while forwarding to
trust-dev commit. It prints a deprecation warning and will not be removed
before 2026-10-05; removal requires a separate behavior-change release note.
ADS¶
Usage: trust-runtime ads <COMMAND>
Current subcommands:
discover: find or identify TwinCAT ADS targets from the current host (ads-wirebuild required).browse: connect to one or all configured ADS client connections inads.tomland print the live symbol table (ads-wirebuild required).doctor: run the ADS connectivity Doctor from the current host (ads-wirebuild required). Supplying--target-net-idmakes a known target a first-class path: the Doctor uses that AMS Net ID instead of requiring UDP identify to succeed. Supplying--write-symbol,--write-type, and--write-valuetogether runs a guarded write probe that writes, reads back, restores, and verifies a safe writable PLC variable.route-script: generate PowerShell, StaticRoutes.xml, GUI, or removal route artifacts using explicit runtime-host identity values.add-route: send UDP AddRoute directly to the PLC. The TwinCAT password is accepted only through--password-stdin.import-symbols: authoring-only live symbol import that can dry-run generatedads.toml, snapshot, and ST files for VS Code/web diff review (ads-wirebuild required).import: generate deterministic ST globals from existingads.tomland cached ADS symbol snapshots.validate --offline: compare generated ST againstads.tomland cached symbol snapshots without opening a PLC connection.validate --live: upload live TwinCAT symbols for each configured connection and compare the checked-in generated ST against the live target (ads-wirebuild required).server status: query[runtime.ads_server]status from a running runtime control endpoint.server symbols: list the runtime globals currently exposed as ADS symbols.server doctor: run the ADS server Doctor against the running runtime. The loopback self-test alone is not external-client proof; pass--external-kindand--external-nameonly after an independent client such as pyads has completed its smoke.server route-script: generate route artifacts for external ADS clients or a TwinCAT engineering station so they can reach the truST ADS server.
The normal customer workflow starts in the VS Code ADS panel or the runtime
host setup page at /setup/ads; the CLI is the scriptable backend. Common
authoring and offline-validation workflow:
trust-runtime ads import-symbols \
--target 192.168.10.5 \
--target-net-id 5.23.91.12.1.1 \
--connection line1 \
--out ads.toml \
--gen src/generated/ads_generated.st
trust-runtime ads validate --offline \
--config ads.toml \
--snapshot ads/snapshots/line1.symbols.json \
--generated src/generated/ads_generated.st
Live validation uses the configured ADS routes:
trust-runtime ads browse \
--config ads.toml \
--connection line1
trust-runtime ads validate --live \
--config ads.toml \
--generated src/generated/ads_generated.st
Live runtime ADS I/O is not started by these CLI commands. It is enabled by
[runtime.ads] in runtime.toml and requires a runtime built with feature
ads-wire.
Offline ads import and ads validate --offline read ads.toml and cached
symbol snapshots without opening a PLC connection. Snapshot arrays are
canonicalized before generation so output is deterministic. Import creates
missing parent directories, reports changed: false when the generated file
already matches byte-for-byte, and refuses to replace different content unless
--force is present. Offline validation requires at least one snapshot and
reports generated-source drift with the first differing line.
Live discovery, browse, Doctor, guarded AddRoute, symbol import, and live
validation fail closed when the binary lacks the ads-wire feature; they do
not synthesize discovery or hardware results and do not write generated files.
Human output summarizes the same report objects emitted by --json; machine
consumers should use --json rather than parse styled terminal text.
ADS server mode is enabled separately by [runtime.ads_server] and requires a
runtime built with feature ads-server. Common server workflow:
trust-runtime ads server route-script \
--route-name trust-runtime-line1 \
--server-ip 192.168.77.10 \
--server-net-id 192.168.77.10.1.1 \
--format powershell
trust-runtime ads server status --project examples/communication/ads_server_basic
trust-runtime ads server symbols --project examples/communication/ads_server_basic
trust-runtime ads server doctor --project examples/communication/ads_server_basic
After an independent pyads smoke, attach that evidence to the Doctor report:
trust-runtime ads server doctor \
--project examples/communication/ads_server_basic \
--external-kind pyads \
--external-name pyads-smoke
The ADS server proof ladder is intentionally split: loopback self-test, pyads independent-client proof, and real TwinCAT engineering-station validation are separate gates.
PLCopen¶
Usage: trust-runtime plcopen [OPTIONS] <COMMAND>
Current subcommands:
profileexportimport
Control¶
Usage: trust-runtime ctl [OPTIONS] <COMMAND>
Important control subcommands:
endpoint [--json]statushealthstatsevents [--limit N]faults [--limit N]io-readio-writeio-forceio-unforcerestartinstall <container> [--restart cold|warm](any--endpoint, alsoserial:///dev/ttyACM0)firmware <image> [--wait <seconds>](a chip's truST firmware, while its program is stopped)device-get,device-set <device.toml>,device-reset(a chip's own settings: name, network, control token, time server, trusted keys; they apply at the chip's next boot)shutdown [--exit]config-getconfig-set
shutdown stops the program and leaves the runtime running in the Stopped state, with its
control server, web UI and other services; restart cold or restart warm starts the
program again. shutdown --exit also ends the runtime's process. Both need the Admin role. A
chip answers --exit as a plain shutdown, because its firmware never ends. The process also
ends on SIGINT or SIGTERM, and trust-runtime fleet runtime stop sends the exit.
firmware updates a chip's truST firmware: the image goes into the firmware slot that does not
run, the chip restarts into it and runs it on trial until its boot is done, and the command waits
until the chip runs it. A firmware that does not finish its boot is rolled back by the chip's boot
loader, and the command says so. The first install on a chip that does not run truST yet goes
through the chip's own boot loader:
trust-runtime firmware install --chip esp32c6 ./trust-firmware-esp32c6
trust-runtime ctl --endpoint serial:///dev/ttyACM0 shutdown
trust-runtime ctl --endpoint serial:///dev/ttyACM0 firmware ./trust-firmware-esp32c6/firmware.bin
A chip whose device.toml names a Wi-Fi network and sets a control token serves its control
connection on that network, by default on TCP port 9901, and ctl reaches it there with the token,
which the chip then also asks for on its USB port. capabilities reports the chip's address:
# device.toml
[network.wifi]
ssid = "plant-net"
password = "the network's passphrase"
[control]
token = "a token of 16 to 128 characters"
trust-runtime ctl --endpoint serial:///dev/ttyACM0 device-set device.toml
trust-runtime ctl --endpoint serial:///dev/ttyACM0 device-reset
trust-runtime ctl --endpoint tcp://192.168.1.50:9901 --token <token> status
ctl --project <dir> endpoint prints the endpoint that a client of the project
uses, and sends nothing to the runtime. With --json it prints
{"endpoint","auth_token","source","endpoint_file_skipped"}, where source is
endpoint_file, configured or default. Every failure prints
{"error":{"code":"<code>","message":"<text>"}} and exits 1. The codes are
no_project, invalid_argument, invalid_config, endpoint_file_invalid,
endpoint_file_unreadable, not_running and default_unavailable; see
runtime.toml.

Figure: The ctl command family and its subcommands for the scriptable
control API. The capture predates ctl endpoint.
Identify¶
Usage: trust-runtime identify [OPTIONS] --duration-s <DURATION_S>
identify makes a runtime show where it is: for the time asked it blinks the
output that the runtime's runtime.toml names in [runtime.identify] output
(an I/O address such as %QX0.7, or a GPIO line such as gpio:17) at 2 Hz. It
works in every state of the resource: running, paused, stopped or faulted. It
needs the Operator role.
Primary options:
--duration-s(required): how long the runtime blinks, a whole number of seconds from 1 through 60.--endpoint: the control endpoint of the runtime,tcp://host:portorunix:///path.--token: the control token. Without it,TRUST_CTL_TOKENis used.--project: a project folder whoseruntime.tomlgives the endpoint and the token that--endpointand--tokendo not.
The command prints the runtime's result as one JSON line,
{"identifying":true,"duration_s":10}. A refused request is a command failure
that prints the runtime's error text and its error code: for example
identify_not_configured for a runtime without [runtime.identify] output
(a chip answers it too until its firmware drives an output), or
identify_output_unavailable when the output cannot be made ready.
Common Flows¶
Build / validate / test¶
trust-runtime build --project ./my-plc --sources src
trust-runtime validate --project ./my-plc
trust-dev test --project ./my-plc --output json
Start runtime¶
trust-runtime play --project ./my-plc
Run agent API¶
trust-dev agent serve --project ./my-plc
trust-runtime agent serve --project ./my-plc remains a compatibility alias
during the product/workbench split. It will not be removed before 2026-10-05,
and removal requires a separate behavior-change release note.

Figure: The agent serve entrypoint and its current stable flags. This is the
CLI contract agents and wrappers should target first.
Serve browser IDE¶
trust-runtime ide serve --project ./my-plc --listen 127.0.0.1:18080
--project defaults to the current directory and may name either one runtime
project or a workspace whose direct child directories are runtime projects. A
root-level runtime.toml is the primary runtime when present; otherwise the
first direct-child runtime.toml in lexical path order is primary. A malformed
selected runtime configuration stops startup. A directory with no runtime
configuration still starts with the neutral config-ui identity so the IDE's
Open Folder flow remains available.
The standalone control state loads the primary project's sources with the same
recursive, case-insensitive .st/.pou discovery and deterministic ordering
used by project builds, including configured local package dependencies. It
serves the IDE in standalone-ide mode with local authentication and does not
start a PLC scan cycle, discovery advertisement, or mesh transport. Runtime
operations that require an executing resource remain unsupported.
trust-runtime config-ui serve forwards to the same implementation and prints
a deprecation warning directing callers to ide serve.