Krux Installer is a GUI based tool to flash Krux without typing any command in terminal for flash the firmware onto the device.
Like Krux itself, this is a research and development project, made by nerds building tools for their own interests, open to the world. Innovative features may have undiscovered flaws that endanger funds. Use it at your own risk.
Since v0.0.22, Krux Installer runs fully offline. The Krux firmware binaries are bundled inside the installer at build time, so it no longer contacts GitHub at runtime — no internet connection is required to flash your device.
Earlier versions fetched the firmware over the network: the installer queried GitHub for the available releases, let you pick a version, then downloaded, verified and unzipped the assets before flashing. All of that runtime networking has been removed. The installer no longer:
- checks your internet connection on startup;
- queries GitHub for the list of available firmware versions;
- downloads, verifies or unzips firmware assets on your machine.
Instead, each release ships with a single firmware version already embedded, verified and unpacked inside the binary. Flashing is now: open the installer → select your device → flash.
Each release ships with a fixed firmware version embedded in the binary
(the current one is v26.09.0). To flash a different firmware version,
download the installer release that bundles it, or build from source with
your desired version (see Firmware embedding (for developers)).
Available for:
- Linux:
- Debian-like;
- Fedora-like;
- In the experimental phase, we have a nix flake for development.
- Windows;
- MacOS:
- intel processors;
- arm64 processors (M1/M2/M3/M4).
Make sure you have python:
python --versionGenerally, all Linux come with python.
Follow the instructions at python.org
Before installing krux-installer source code, you will need prepare the system:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"brew install pythonand add this line to your ~/.zshrc:
alias python=python3Python's ssl module relies on OpenSSL for cryptographic operations.
Ensure that OpenSSL is installed on your system and is compatible with the
Python version you're using.
Since we expect that you're using the Python installed with Homebrew, it's recommended to install OpenSSL through Homebrew if it's not already installed:
brew install opensslAfter installing OpenSSL, make sure it's linked correctly:
brew link --force opensslThis ensures that the OpenSSL libraries are available in the expected locations that Python can find and use.
Library paths on MacOS involves verifying that the environment variables and system
configurationsare correctyly set to find the necessary libraries, such as OpenSSL,
which is crucial for the ssl module in Python.
On MacOS, the dynamic linker tool dyld uses environment variabes to locate shared
libraries. The primary environment variable for specifying library paths is
DYLD_LIBRARY_PATH.
Adding the lines below to your ~/.zshrc (or similar) the DYLD_LIBRARY_PATH
will be set each time you open a new terminal session (and therefore the OpenSSL
libraries libcrypto.dylib and libssl.dylib will can be found):
OPENSSL_MAJOR_VERSION=`openssl --version | awk '{ print $2}' | cut -d . -f1`
OPENSSL_FULL_VERSION=`openssl --version | awk ' { print $2}'`
export DYLD_LIBRARY_PATH="/opt/homebrew/Cellar/openssl@$OPENSSL_MAJOR_VERSION/$OPENSSL_FULL_VERSION/lib:$DYLD_LIBRARY_PATH"Follow the steps to install UV on [https://docs.astral.sh/uv/reference/storage/]
Clone the repository:
git clone --recurse-submodules https://github.com/selfcustody/krux-installer.gitInstall python dependencies:
uv sync --frozenIf already cloned the repo without using --recurse-submodules,
use the command below to clone the needed submodules:
git submodule update --initKrux-Installer uses poe task manager for formatting, linting, tests,
coverage and build.
uv run poeRunning formatting, linting and tests together before commiting is a good way to mitigate before commit it:
uv run poe pre-commitRunning this locally mirrors the core CI code checks, except for commit message format and changelog requirements. It helps prevent failed PR builds and ensures that changes follow the contribution guidelines. Depending on the change, a changelog entry may also be required.
To run these checks automatically, install the pre-commit hooks:
uv run pre-commit installAfterwards, each commit runs lint and format checks and each commit message is checked against the conventional-commits.
Each push additionally runs the full test suite, mirroring what CI enforces. This also encourages reviewing your own changes before pushing. You can run manually with:
uv run pre-commit run --all-filesuv run poe formatuv run poe lintuv run poe testFor systems without a window manager:
# Linux only
uv run poe test --no-xvfbYou can see all coverage results opening you browser and type
file:///<folder>/krux-installer/htmlcov/index.html (assuming
folder is where you placed the krux-installer project).
uv sync --frozen --extra builder
uv run poe fetch-firmware
uv run poe build-linuxuv sync --frozen --extra builder
uv run poe fetch-firmware
uv run poe build-macosuv sync --frozen --extra builder
uv run poe fetch-firmware
uv run poe build-winIt will export all project in a
one-file binary:
- linux:
./dist/krux-installer - macOS:
./dist/krux-installer.app/Contents/MacOS/krux-installer - windows:
./dist/krux-installer.exe
To more options see .ci/create-spec.py against the PyInstaller options.
The installer ships with firmware binaries embedded at build time. This section documents how the embedding pipeline works and how to use locally built binaries for development or testing.
prebuild/
└── fetch_firmware.sh # canonical script: download → verify → embed
.firmware_download/ # landing folder (gitignored)
└── <version>/
├── krux-<version>.zip
├── SHA256SUMS
└── SHA256SUMS.sig
src/utils/firmware/ # packing folder (committed, embedded in the binary)
└── <version>/
├── amigo.kfpkg
├── bit.kfpkg # not present in all releases
├── cube.kfpkg
├── dock.kfpkg
├── embed_fire.kfpkg
├── m5stickv.kfpkg
├── tzt.kfpkg
├── wonder_k.kfpkg
├── wonder_mv.kfpkg
└── yahboom.kfpkg
The .firmware_download/<version>/ landing folder holds the raw assets from
GitHub (zip, SHA256SUMS and its signature). It is gitignored and can be
deleted after a successful build. The public key is not downloaded: the
script uses the selfcustody.pem committed to this repository.
The src/utils/firmware/<version>/ packing folder contains only the
extracted .kfpkg files — one per supported device. These are committed
to the repository and embedded into the installer binary by PyInstaller
at build time.
uv sync --frozen --extra builder
uv run poe fetch-firmwareThis runs prebuild/fetch_firmware.sh, which:
- Downloads the release zip,
SHA256SUMSandSHA256SUMS.sigfrom GitHub into.firmware_download/<version>/; - Verifies the ECDSA signature of
SHA256SUMSwithopenssl, against the committedselfcustody.pem; - Verifies the zip against its entry in
SHA256SUMS(sha256sumon Linux,shasumon macOS); - Extracts
kboot.kfpkgfor each supported device and saves it assrc/utils/firmware/<version>/<device>.kfpkg; - Writes
src/utils/firmware/<version>/SHA256SUMSandsrc/utils/firmware_hashes.py, the table the app checks before flashing.
Since v26.09.0 the signature covers SHA256SUMS, not the zip itself.
SHA256SUMS.asc (the release manager's GPG signature) is not used.
Required tools in PATH: curl, unzip, openssl, sha256sum/shasum.
Verification fails closed if any of them is missing.
If you are developing Krux firmware and want to test your locally compiled
binaries with the installer, place your .kfpkg files directly into the
packing folder — no download step needed:
src/utils/firmware/<version>/
├── amigo.kfpkg ← your locally built binary
└── ...
The version directory must match the FIRMWARE_VERSION constant in
src/utils/constants/__init__.py. When running the installer from source
(uv run poe dev), it will pick up whatever .kfpkg files are present
in that folder.
Note: locally built binaries are unsigned. The installer will still flash them correctly; only the pre-build verification step (
fetch_firmware.sh) requires a valid signature. No signature is checked at flash time.
To test a release before its tag is published — when fetch_firmware.sh has
nothing to download — use uv run poe generate-checksums --source <krux-build-dir>
to embed a local build and generate its hash table. See
pre-release-workaround.md.
After building the installer, the landing folder is no longer needed:
rm -rf .firmware_download/The packing folder (src/utils/firmware/) should be kept as-is if you
want to commit the firmware files for reproducible builds.
