Switching the host release to the Rust tools and applications
Proposed and accepted 2026-10-31. The next host release, v4.0, ships the Rust applications
(Tag Programmer, Tag Monitor, Tag Calibrator, Tag View) and the Rust
command-line tools in place of the Qt applications and the C++ tools that
have Rust equivalents. The C++ that has no equivalent stays and ships:
dataprocessing, tag-txt-import, and the tagcore_c library the Rust
programs link. The C++ tools that exist only for the bench and have no port
(the recovery tools) stay in the default build in bin/internal. Everything
replaced moves behind one CMake option, BUILD_LEGACY_HOST, off by default,
so it can still be built for reference, for regenerating test oracles, and
for a fallback release.
The one dependency this removes is Qt, with everything attached to it
(aqt in CI, macdeployqt and windeployqt, the QML import checks, the Qt
notices and the GPL section of the licence index, QCustomPlot). The vcpkg
dependencies (libusb, protobuf, sqlite3) cannot go: tagcore_c
carries protobuf and SQLite inside it for Tag Monitor's downloads, Tag
Calibrator and Tag View; dataprocessing and tag-txt-import need protobuf
and SQLite; and the recovery tools need the C++ tagcore, which needs
libusb. The section Dependencies says what could still be
trimmed and at what cost.
What ships after the switch
| Product | Today | After | Notes |
|---|---|---|---|
| Tag Programmer | qtprogram.app and tagprogram.app |
tagprogram only |
Programs through probe-rs; STM32CubeProgrammer is no longer needed on a station |
| Tag Monitor | qtmonitor and tagmonitor |
tagmonitor only |
Downloads through tagcore_c |
| Tag Calibrator | qtcalibrate and tagcalibrate |
tagcalibrate only |
Calibration is the same C++ session, through tagcore_c |
| Log viewer | sensorviz and tagview |
tagview only |
Same C++ core; the Qt-only activity filter is not carried in this release (decided, see gaps) |
| Bit Tag Visualizer | btviz |
removed | Deprecated; the source in host/applications/btdataviz is deleted, its logs open in Tag View |
tag-info, tag-start, tag-stop, tag-reset, tag-test, tag-cal, tag-dwnld |
C++ | Rust, same names, options, output and exit status | tag-dwnld links tagcore_c |
tag-flash, base-flash |
Rust | Rust | unchanged |
dataprocessing, tag-txt-import |
C++ | C++ | no Rust equivalent; tag-txt-import needs the C++ text-log reader |
tagcore_c |
shared library on Linux and Windows, static on macOS | same | now linked by tag-dwnld as well |
| User manual | pages for both lines | the Rust applications' pages; the Qt pages kept for this one release under a "Legacy" heading | see Documentation |
Built but not installed, in bin/internal, unchanged: the C++ recovery tools
tag-capture, tag-xflash, tag-sramcall, tag-rebuild, and
tag-log-import (or its Rust replacement, below). The Rust bench tools
(tag-peek, tag-attach-cycle, tag-monitor-test, tag-side-channel-check,
tag-test-example, tag-cal-write, qtmonitor-fixture-capture) are built
into bin/internal too, so the bench scripts that run tools by path keep
working.
Behind BUILD_LEGACY_HOST=ON (default OFF): the five Qt applications,
sensorui, qcustomplot, sensoranalysis's Qt layer and its Qt-comparing
test programs, host/common, and the thirteen C++ command-line tools that
have Rust equivalents. The option requires Qt, exactly as BUILD_QT_APPS
does today.
Dependencies
| Dependency | Needed by, after the switch | Removable? |
|---|---|---|
| Qt 6.10.3 (and the aqt install, deployment tools, QML checks, Qt and QCustomPlot notices) | nothing in the default build | Yes. Only BUILD_LEGACY_HOST looks for it |
vcpkg protobuf |
tagcore_c (the SQLite writer parses the protobuf wire bytes; sensoranalysis_core_json reads calibration JSON), dataprocessing, tag-txt-import, the recovery tools |
No |
vcpkg sqlite3 |
tagcore_c (writer, sensordata), dataprocessing, tag-txt-import, tag-rebuild |
No |
vcpkg libusb |
the C++ tagcore link layer: the recovery tools (SwdSession), tag-txt-import (links tagcore whole), and tagcore_c (links tagcore whole for writeHeader(Tag &), which nothing calls) |
Not while the recovery tools are C++. tagcore_c could stop carrying it by moving writeHeader(Tag &) and readTagLogHeader() out of the writer's files, which the tagcore-c design already lists; that shrinks the library but does not remove the vcpkg port |
vcpkg pkgconf (host) |
finding libusb off Windows | stays with libusb |
| WebKitGTK 4.1 (Linux), WebView2 (Windows) | the four Tauri applications | already required |
| Rust 1.85+ | everything Rust | already required; becomes mandatory for the default build rather than skipped when missing |
So the vcpkg manifest is unchanged. What the switch saves on a build machine and in CI is Qt: the largest install, the deployment steps, and the licence complications. Dropping libusb too would mean porting the recovery library (the last large piece of C++ with no Rust equivalent); that is a separate proposal and not part of this release.
Gaps to close before the release
These are the items the Rust side has recorded as unfinished or unchecked. Each is small; together they are the first phase.
- The Rust command-line tools are not installed by CMake. Only
tag-flashandbase-flashare. The build must produce, sign and install the seven shipped tools from thetag-toolscrate, withtag-dwnldlinkingtagcore_c(static on macOS; on Linux an rpath of$ORIGIN/../lib, whichcommandline-rs/build.rsdoes not yet set fromTAGCORE_C_RPATHas the applications' build scripts do; on Windows the DLL beside the executable, which means the launcher arrangement the applications use). - Hardware checks not yet run, from the Rust READMEs:
tag-start --configand--mergeon a tag;tag-teston an IMUTag; the opt-in write, start and unplug checks oftag-side-channel-check; programming an STM32U375 through Tag Programmer's engine (Retest has passed, Program has not been run); Tag Calibrator and Tag View on Windows and Linux packages beyond "starts and stays up". - Test oracles that need the Qt applications. Tag Monitor's 710
configuration-probe goldens are generated by
qtmonitor --config-probe, Tag Calibrator's replay log is compared with qtcalibrate's, and Tag View is compared with the Qtsensorvizthroughsession_cli. The committed goldens and logs keep the Rust tests running without Qt; regenerating them needsBUILD_LEGACY_HOST=ON. The test READMEs must say so, and the procedure intagmonitor-rs/design/adding-a-tag-type.mdbecomes "build the legacy qtmonitor to regenerate goldens" until a Rust probe replaces it (not part of this release). - Tag View's missing activity filter. The Qt
sensorvizhas an activity filter that the toolkit-neutral core deliberately left in the Qt layer. Shipping Tag View alone drops the feature. Decided 2026-10-31: release without it. The Tag View manual page says so, and porting it into the core (the proposaltoolkit-neutral-core.mdreserved it) goes tohost/applications/sensorviz-rs/TODO.mdfor a later release. tag-log-import. Promotetaglogwriter'slog-importexample to atag-toolsbinary of that name (an afternoon), so the only C++ tools left outside the legacy option aredataprocessing,tag-txt-importand the recovery tools. It stays internal (decided 2026-10-31): built intobin/internal, not installed, no manual page.tagsimfinds it throughTAG_LOG_IMPORT_BINorPATH, so nothing else changes.- Screenshots for the manual. The Rust applications' pictures come from
their mocks (
ui/screenshots.sh); the Qt pages' pictures came from the Qt applications' capture modes, whichlinux-package-test.shalso runs as a smoke test. Those captures go with the pages; the package test needs a Rust-side replacement for "the application draws its window" (the existingrun_stays_upchecks, plus one headless capture per application if wanted). - The release procedure's counts and checks. "Seven app lines" becomes
four;
verify-macos-dmg.shapplies its Qt TLS-plugin check only to bundles containing QtCore and so needs no change, but the bundle list it expects does;linux-package-test.sh's TLS-plugin check (for qtprogram's GitHub listing) becomes "tagprogram lists releases", which Tag Programmer'ssmokeexample can drive.
The work, in phases
Phase 1: close the gaps
host/commandline-rs/build.rs: honourTAGCORE_C_RPATHfor every binary of the crate (not onlytag-dwnld), as theappbuild scripts do.host/commandline-rs/src/bin/tag-log-import.rs: thelog-importexample as a tool, built with thesqlitelogfeature; retire the C++ one into the legacy option.- Run the recorded hardware checks (item 2) on the bench, per
docs/bench/, and record the results in the READMEs' status sections.
Phase 2: CMake
CMakeLists.txt(top level): addoption(BUILD_LEGACY_HOST "Build the Qt applications and the C++ tools that the Rust programs replace" OFF). MakeBUILD_QT_APPSfollow it (keep the name as an alias for one release, with a warning, so presets and scripts that set it still work).BUILD_HOST_DOCSno longer defaults fromBUILD_QT_APPS; default it ON.BUILD_RUST_APPSbecomes ON regardless of whether cargo is found, with the error message pointing at rustup (a host build without Rust is now not a host build); keep an explicit-DBUILD_RUST_APPS=OFFfor firmware-only machines.host/CMakeLists.txt:libraries/qcustomplot,libraries/sensorui, the four remaining Qt applications andhost_common's Qt definitions underBUILD_LEGACY_HOST;applications/btdatavizdeleted outright (decided 2026-10-31), with its entry inhost_qt_install_targets, its manual pageapps/btdataviz.mdand images, and its notices;git logkeeps the source if it is ever wanted;host_qt_install_targetsempty unless legacy;host_cli_install_targetsreduced totag-txt-importanddataprocessing(C++), and a new list of the Rust tools installed from thetag-toolsbuild;- the macOS code-signing loop extended to the Rust tools (as
commandline-rs/CMakeLists.txtalready does fortag-flash), the Windows launcher arrangement fortag-dwnld(which needstagcore_c.dllbeside it intag_tools/lib), the Linux install intotag_tools/bin. host/commandline/CMakeLists.txt: the thirteen replaced tools underif(BUILD_LEGACY_HOST);dataprocessing,tag-txt-importand the recovery tools unconditional.cmake/HostRust.cmake: ahost_rust_tools()function (or extendrust_flash_tools()) that builds the wholetag-toolscrate with--features sqlitelogonce, copies the shipped tools tobin/and the bench tools tobin/internal/, and depends ontagcore_c_staticortagcore_c.flash_toolsfolds into it; the embedded targets' dependency name is kept.host/libraries/sensoranalysis/CMakeLists.txt: the Qt layer and the Qt-comparing tests (calibration_dump,compass_core_parity_check,capture_replay) under the legacy option;sensoranalysis_coreandsensoranalysis_core_jsonstay.host/applications/sensorviz/CMakeLists.txt: the Qt application under the option;core/stays (Tag View's).cmake/CheckQmlImports.cmake,DeployQt*.cmake,PruneMacosQml.cmake: unchanged, used only under the option.
Phase 3: CI and release tooling
.github/workflows/release.yml: remove the Qt install step andQT_VERSIONfrom the default matrix; configure with-DBUILD_LEGACY_HOST=OFF; keep one optional job (manual dispatch) that builds the legacy configuration so it does not rot. Remove theREPRODUCIBLE_BUILDQt-version check from the default path (it stays in CMake for the legacy build).host/tools/linux-package-test.sh: the tool list adds nothing (same names); drop the Qt TLS-plugin check and the Qt application captures; add the Rust applications' headless checks (and atagprogramrelease-listing check if its mock orsmokeexample can be driven in a container).host/tools/verify-macos-dmg.sh: expect four bundles; the per-bundle Qt checks stay conditional.host/tools/release-macos.sh,sign-ci-macos.sh: no change expected (they sign whatever is in the image); confirm.docs/release/release-procedure.md: the app count, the smoke-test list (launch the four applications,tag-info --help,dataprocessing --help), and the Qt pin table entries marked legacy.LICENSES/host/README.md: the GPL section goes (no QCustomPlot, no Qt Quick 3D in the default packages); the Qt and QCustomPlot rows move to a "legacy build only" note or go;Qt-THIRD-PARTY-NOTICES.txtis no longer installed by default. The Rust notices are regenerated as usual.
Phase 4: documentation
User manual (host/docs/):
mkdocs.ymlnav andsrc/index.md: one entry per product, pointing at the Rust applications' pages (tagprogram.md,tagmonitor.md,tagcalibrate.md,tagview.md). Decided 2026-10-31: keepqtprogram.md,qtmonitor.md,qtcalibrate.mdandsensorviz.mdfor this one release under a "Legacy" heading in the nav, each with a note at the top that the program is no longer in the packages and is built only withBUILD_LEGACY_HOST; remove them and their images (theqtmonitor-*,qtcalibrate-*,qtprogram-*,sensorviz-*,TagMonitor*files) in the release after.btdataviz.mdand its images go now, with the program.workflows/*.md: name the Rust applications; the firmware-programming workflow drops STM32CubeProgrammer.cli/*.md: the pages describe behaviour the Rust tools share; add the Rust-only differences (option errors exit 2);tag-dwnld.mdnotes the file is written by the same writer.tag-log-importstays internal and gets no page.reference/config-files.mdalready names Tag Monitor; check the remaining pages for "qtmonitor".
Developer documentation:
host/README.md,host/applications/README.md,host/libraries/README.md,host/AGENTS.md: "both ship" becomes "the Rust applications ship; the Qt applications build withBUILD_LEGACY_HOSTfor reference and oracles".- The guide: chapter 1 (two implementations), 2 (the tree), 9 (which tools are installed), 11 (the Qt applications, briefly), 12 (Qt row), 13 (options, packages, CI). One pass through each.
docs/architecture/overview.mdhost paragraph; the rootREADME.mdprerequisites (Qt only for the legacy build; Rust required).- Each Rust application's README: status "shipped as the product".
docs/decisions/0042-host-rust-default-release.md: this plan as carried out, with the evidence.docs/bench/*.mdandembedded/tools/*.pydocstrings that say "detach qtmonitor": "detach Tag Monitor (tagmonitor)"; thepgreppattern inpower-testing.mdgainstagmonitor.
Phase 5: the release
Follow docs/release/release-procedure.md with the updated checks. The
version is v4.0 (decided 2026-10-31): the package is at v3.5, and a
release that changes every application's implementation and drops Qt is a
major one. Steps particular to this release:
- Tag firmware is unchanged; no firmware qualification is needed unless a firmware fix is folded in.
- Build the three packages on CI with the default (Rust) configuration;
run
linux-package-test.sh; sign and notarise the macOS image locally. - On the bench, with the installed package: program a tag with Tag Programmer, configure and start it with Tag Monitor, stop and download it, erase it, view the download in Tag View, calibrate a CompassTag or IMUTag with Tag Calibrator and write the constants; run each shipped command-line tool once against a tag. Record the results in the release.
- Release notes: the Rust applications replace the Qt ones; the names of the executables; STM32CubeProgrammer no longer required; the activity filter's status; the legacy build option for anyone who needs the Qt programs.
Checks that say it is done
- [ ] A default configure on a machine without Qt succeeds and builds every
shipped program and
bin/internal. - [ ]
BUILD_LEGACY_HOST=ONbuilds the Qt applications and the replaced C++ tools as before, and the oracle regeneration procedures work. - [ ]
cmake --installlays outtag_toolsas the packaging tables say on all three platforms;ldd,otool -Land the DMG verifier are clean. - [ ]
linux-package-test.shpasses in clean containers. - [ ] The bench checklist of phase 5 passes with the installed package.
- [ ]
docs.py checkpasses; the manual builds; no page names a Qt application as current. - [ ] The notices files match the lock;
LICENSES/host/README.mddescribes the packages as built.
Risks and the fallback
- A regression in a Rust tool found in the field. The legacy option builds the C++ tool of the same name; a fix can ship either as a Rust fix or, worst case, as a legacy build. Keep the option working for at least this release and the next.
- Windows. The Rust tools have been proven on Windows for
tag-flashand the applications;tag-dwnldwithtagcore_c.dllon Windows has not been exercised in a package. Phase 1 covers it; the package test on Windows is manual. - Users with scripts calling the C++ tools by path are unaffected: names
and output are the same, and
bin/is the same place. - CI without Qt is faster and simpler, but the legacy job must still run occasionally or the legacy build rots; a monthly or manual-dispatch job is enough.
Decisions
Settled 2026-10-31:
- Tag View's activity filter: release without it; port it later.
- The Qt manual pages: keep one release under a "Legacy" heading, then remove.
btviz: delete the source; its logs open in Tag View.tag-log-import: Rust, but internal (bin/internal, not installed).- The version number:
v4.0.
Nothing is open; the work can start with phase 1.
Effort
| Phase | Estimate |
|---|---|
| 1. Gaps (without the activity filter) | 2 to 3 days, one of them on the bench |
| 2. CMake | 1 day |
| 3. CI and release tooling | 1 day, plus CI runs |
| 4. Documentation | 1 to 2 days |
| 5. Release | the procedure's usual day, plus the bench checklist |