The engine, and how it keeps a stick safe
install.sh and refresh.sh are thin wrappers around helix, a single
standard-library Python script:
| Command | Does |
|---|---|
helix list |
every tool, its source, and whether it’s enabled |
helix check [--json] [--outage-ok] |
compares your cache against upstream, no downloads |
helix fetch [tool…] [--force] [--outage-ok] |
downloads, verifies and caches (~/.cache/helix-boot); resumes interrupted downloads; when a tool’s site is down, keeps the copy already verified |
helix sync <mount> [--dry-run] [--verify] [--prune-unknown] |
copies the cache to a Ventoy stick, replaces old versions, writes the menu; --dry-run ends with what it would copy, remove and keep |
helix pack [file.zip] [--public] [--split [GiB]] [--need-app] |
the whole stick, your own tools and Ventoy in one zip, named helix-boot-<version>-<date>.zip |
helix unpack <pack.zip> <mount> [--dry-run] [--verify] [--prune-unknown] |
fills a Ventoy stick from a pack, no downloads |
helix theme <mount> [--theme ID] [--icons ID] [--background PIC] [--splash PIC] [--menu] [--preview FILE] |
shows or changes a stick’s look (themes); --export ZIP / --import ZIP save and load it |
helix verify <mount> [--json] |
reads the stick back and finds damaged or missing files, no downloads (checking a stick) |
helix self-update --asset NAME --program FILE |
replaces a downloaded Helix Boot program with the latest release’s, verified |
helix test <mount> [--gb N] |
writes the stick’s free space full, reads it back and deletes it: finds a failing or fake stick (testing a stick) |
helix splash <VTOYEFI mount> |
adds the splash to Ventoy’s boot script (install.sh and refresh.sh run it) |
linux/helix_gui.py is the Windows app’s window on Linux. It imports
windows/helix_boot.py and replaces what is Windows’ own: the list of disks
(lsblk), where a stick’s files are (its mount point, through udisks),
Ventoy’s installer (its Linux script, as root through pkexec) and Repair
stick (fsck). The window, the install and update steps and their safety
checks are the same code on both systems.
Only those two steps run as root. Your cache is yours to write, so root is
never pointed at a script in it: it gets Ventoy’s archive and the checksum
Ventoy publishes for it, copies the archive to a folder only root can write,
checks the copy, unpacks it there and runs Ventoy’s script from there. The
checksum is listed in linux/helix_gui.py (VENTOY_SHA256); for a Ventoy
newer than the list it is fetched from Ventoy’s release page at that moment,
and without either the window refuses and points to install.sh. What the
cache or a pack records about its own Ventoy is not used: whoever could change
the archive there could change that too. scripts/release.sh stops if the
current Ventoy isn’t listed. Root’s own programs (pkexec, fsck) are taken
from the system’s folders, never found on your PATH.
theme.sh and check.sh wrap helix theme and helix verify the same way:
they find and mount the stick first.
Pillow is the one optional extra: with it the engine draws previews, the
splash’s loading bar and greyscale icons, and resizes your pictures; without it
those are skipped and everything else works.
Verification
Section titled “Verification”Each tool lists checksum strategies in order of preference. The first one that yields a hash is used; a mismatch deletes the file and stops:
- the publisher’s checksum file (
sha256.txt,CHECKSUMS.TXT,*.sha512) - GitHub’s recorded sha256 digest for the release asset
- SourceForge’s md5 (integrity only)
tofu: trust-on-first-use, only if the manifest explicitly says so. The hash is recorded, and a re-download of the same version with a different hash is refused as possible tampering.
If no strategy works, the tool is refused rather than silently used.
Checking a stick
Section titled “Checking a stick”Cheap USB sticks can go bad without warning: a file reads back wrong, and a
tool fails to boot just when you need it. ./check.sh (or Check stick in
the app) reads every boot image and app back off the stick. It compares them
with the checksums recorded when they were copied. Those come from the download
or the pack, never from the stick itself. It needs no cache and no internet,
so any PC can check any Helix Boot stick. It takes about as long as copying
the stick.
A damaged image is noted on the stick, and the next update copies it again,
even a quick one. An app file that differs is reported separately, because
some tools save their settings in their own folder; it still counts as a
finding (helix verify exits non-zero, and the app shows it as a problem),
since a changed program file looks the same.
The stick remembers the days a check found files gone bad. Once can be a bad write or a stick pulled out too soon. If it happens again after an update repaired it, the check says so and says to replace the stick.
A stick whose filesystem is damaged is another matter: files can’t be read at
all (an “Input/output error”), and an update can’t fix that. The engine, the
Windows app and the Mac tool then stop and give the repair command for the
system they run on (fsck on Linux, chkdsk on Windows, diskutil repairVolume on a Mac). Repair it, update, and check the stick.
A check is only useful if it happens. The stick records the day it was last read back in full, and an update says so once that is over 30 days ago.
Testing a stick
Section titled “Testing a stick”helix test <mount> (./install.sh --test, helix-mac install --test, or
Install tests the stick first in the Windows app) is for a stick you are
about to trust. It fills the free space with data that is different in every
megabyte, reads all of it back from the stick itself, and deletes it. A stick
that drops writes fails, and so does a fake that claims more room than it has:
those wrap round and overwrite what they were given, so the first megabytes
read back wrong. Nothing already on the stick is touched. An installer that
runs the test stops before copying anything onto a stick that fails. It writes
and reads the whole stick, so expect it to take as long as two full copies.
--gb N tests only the first N GiB, which is quicker but can’t find a fake.
A stick and a virtual machine
Section titled “A stick and a virtual machine”A stick attached to a virtual machine while this system has it mounted is written by two systems at once, which corrupts its filesystem. On Linux the scripts and the window look at libvirt’s VMs first (the system’s through its read-only door, so no password is asked; yours if its service is running). They stop if a running VM has the stick as a disk, and warn if a VM is set to take it when it starts.
To use the stick in a VM, hand it over: scripts/vm-stick.sh give win11
unmounts it here and attaches it to the running VM; eject it inside the VM
when you are done, then scripts/vm-stick.sh take win11 detaches it. A stick
that Windows ejected has switched itself off, so take asks you to unplug it
and plug it in again, and mounts it here when it is back.
When a tool’s site is down
Section titled “When a tool’s site is down”A site that answers with a server error, or not at all, is tried four times. If
it stays down, helix fetch keeps the copy of that tool it fetched and verified
before, says so, and carries on; an update of your stick then uses that copy.
Only a tool never fetched on this PC is reported as failed. --outage-ok turns
that failure into a warning too, and helix check --outage-ok does the same
for a site it can’t ask. CI uses both on a push, where an outage elsewhere says
nothing about the commit; its weekly run stays strict, so a site that is gone
for good still shows.
Releasing
Section titled “Releasing”scripts/release.sh 0.7.1 "what is new" does a release in the one order that
works. It checks that main is clean, pushed and passes the tests, waits for
CI on that commit and stops unless every run passed, moves
CHANGELOG.md’s Unreleased section under the new version, shows the release
notes and asks, then commits, tags and pushes. It waits for the build on GitHub
to publish the release, and only then fetches and makes the pack
(helix pack --need-app), so the pack carries that release’s HelixBoot.exe.
A pack made too early would carry the one before; helix pack warns when that
happens. --no-pack skips the pack and scripts/release.sh --pack makes only
the pack.
An update with --verify (install.sh always, refresh.sh --verify, and
every Update from the Windows app) checks the apps’ files as well as the boot
images, and copies an app again when any of its files is missing or differs.
That puts back settings a tool saved in its own folder, so copy those off
first if you want to keep them.
Apps copied by Helix Boot 0.6.5 or older aren’t recorded yet. The next update records them.
Safety
Section titled “Safety”install.shdownloads and verifies everything before touching any disk.- It lists only USB/removable disks and refuses any disk holding your running system, following LUKS, LVM and btrfs back to the physical disk.
- You type the device name to confirm, and it warns if the “stick” is
suspiciously large. A new stick is named
HelixBoot(stick_labelunder[settings]), and is recognised later whatever you rename it to. refresh.shremoves a tool from the stick only when it brings a newer copy of it, the tool is switched off, or this PC put it there and no longer has it. The stick records which PC put each tool on it, so updating from a second PC leaves the first one’s tools alone (more).- Nothing read from a pack or from a stick (paths, app names) can reach outside the stick: a crafted pack or a stick tampered with on an infected PC can’t write or delete anything else.
- Lazarus PE and the Helix Apps menu only accept a USB/SD disk as the stick
(tag file, no Windows on it), so a tag planted on the PC being repaired can’t
get its script run. They need PowerShell to tell which disks are USB; where
it’s missing they run nothing by themselves, and you open the stick’s
Appsfolder by hand. - The disk you confirm is the disk that gets written. Between your confirmation and each write, the scripts and the Windows app check it is still the same device (Linux: the kernel’s disk sequence number; Windows: its serial, or the device id Windows gave it), still USB, and not the system disk. A stick swapped under the same name stops the run.
- A stick is only written if it is a plain file tree. A symlink, a Windows reparse point or a hard link anywhere on it is refused before anything is changed, since one could send a write somewhere else. Keep the stick mounted by one system only while it’s updated.
- Files are written under a fresh, unguessable temporary name and then moved into place, so nothing planted under a predictable name gets written through.
refresh.sh --dry-runchanges nothing, so it can’t be combined with--upgrade-ventoyor--eject.
Updating from more than one PC
Section titled “Updating from more than one PC”An update removes a tool from the stick only when it brings a newer copy of
that tool, you switched the tool off in local.toml (enabled = false), or
the PC that put it there no longer has it. Tools from another PC stay where they are, with their
names, tips and icons in the menu: your paid tools when you update from the
Windows app on a second machine, or a tool whose download just failed. The run
lists what it kept; ./refresh.sh --prune-unknown removes them. The stick’s own
icons and splash stay the same way when the updating PC has none of its own.

