← Back
irpina

irpina/elekloader

A mod loader for Elektron firmware. You pick mods and supply the stock OS file Elektron publishes for your device. elekloader builds a custom OS file on your own machine, and you flash it the way you flash any OS update.

View on GitHub ↗
Stars
37
Forks
3
Watchers
37
Open issues
2
Contributors
1
Language
Python
License
GNU General Public License v2.0
Default branch
main
Created Sep 26, 2026Updated Oct 2, 2026

Star growth

Today—
This week—
This month—

Star history will appear here once this repo has been tracked for a couple of days.

README

elekloader

A mod loader for Elektron firmware. You pick mods and supply the stock OS file Elektron publishes for your device. elekloader builds a custom OS file on your own machine, and you flash it the way you flash any OS update.

  • Nothing from Elektron is distributed. A mod (.elemod) carries only its author's bytes, the short instruction fragments needed to hook the OS, and hashes of the stock bytes it expects. Every build starts from your own stock file, recognised by its hash.
  • The bootloader is never touched. Mods can only change the main OS: the file format has no way to say anything else. Each output file is re-read and verified before it is written. So the stock OS file always recovers the device.
  • Mods are checked against each other before anything is built. Two mods may not touch the same bytes, claim the same memory or the same named resource, or leave a requirement unmet.
Device OS Status
Digitakt (mk1) 1.53, 1.54 supported
Digitone (mk1) and Digitone Keys 1.43, 1.44 supported
Octatrack (MKI and MKII) 1.40C supported: whole builds (format-1 mods); linkable mods with its own core, checked in an emulator, not yet on a unit
other Elektron devices planned: see docs/DEVICES.md

Install

In your browser, nothing to install: https://irpina.github.io/elekloader/. Drop in your stock OS file, add your mods or browse the mod shop, tick them, build, and download the .syx (and, for the Octatrack, the .bin). The build runs in the page, in Python compiled to WebAssembly (Pyodide), with elekloader's own code, unchanged. The page shows its version and commit, and whether that is the latest release's. Your files are never uploaded, the site hosts no firmware, and it fetches nothing from any other site. The latest release's core for your device is listed and ticked for you. See docs/WEB.md.

Windows: download elekloader-<version>-windows.exe from Releases and run it. There is nothing to install and no Python needed. The first time, it asks for your stock OS file (below). The core mod is built in: it is listed in the window, and ticked for you with any mod that needs it. The exe is not signed, so Windows may say it protected your PC: choose More info, then Run anyway.

macOS: download elekloader-<version>-macos.dmg from Releases, open it, and drag elekloader to Applications. It runs on Apple silicon and Intel Macs, with no Python needed, and it is signed and notarized by Apple. As on Windows, the first time it asks for your stock OS file, and core is built in.

Any system, from source: Python 3.9 or newer, nothing else to install (on Linux, Tkinter may be a separate package, such as python3-tk). Download or clone this repository, then:

python -m elekloader                        # the window
python -m elekloader.patch --stock Digitakt_OS1.53.syx --mod core-2.1.elemod --mod a.elemod --out custom.syx --version 2.0a
python -m elekloader.patch --stock Digitakt_OS1.53.syx --mod core-2.1.elemod --mod a.elemod --check

With pip install . the same commands are elekloader and elekpatch. From source, core is not built in. Take your device's from Releases (or build it, below), and install it like any mod. There is one per device and OS:

device OS core
Digitakt mk1 1.53 core-2.1.elemod
Digitakt mk1 1.54 core-2.1-os1.54.elemod
Digitone mk1, Digitone Keys 1.43 core-dn1-2.0a.elemod
Digitone mk1, Digitone Keys 1.44 core-dn1-2.0a-os1.44.elemod

A mod is made for one OS version: one built for 1.53 is refused with a 1.54 stock file, and its author has to build it for 1.54 (docs/ADAPTING.md, "Another OS version").

You also need the stock OS file for your device, exactly as Elektron publishes it:

  • Digitakt mk1: Digitakt_OS1.54.syx or Digitakt_OS1.53.syx, from Elektron's Digitakt downloads;
  • Digitone mk1 or Digitone Keys: Digitone_and_Digitone_Keys_OS1.44.syx or ..._OS1.43.syx (one file serves both), from Elektron's Digitone downloads;
  • Octatrack MKI or MKII: OCTATRACK_OS1.40C.syx or OCTATRACK_OS1.40C.bin (one file serves both), from Elektron's Octatrack downloads.

The .zip Elektron's site gives you works as it is. elekloader recognises the file by its hash.

Build a custom OS

  1. Your stock OS file: the first time, elekloader asks for it (a .syx, a .bin or Elektron's .zip); Change stock firmware... (top right) picks another. The header then shows the device and OS version with a tick. Mods made for another device or OS version are hidden unless you tick Show mods for other firmware.
  2. + Install from file...: add the .elemod files of the mods you want. They are copied into your library.
  3. Tick the mods (or double-click them). Each mod's status shows as you go: Enabled, Conflict, Needs another mod, or made for other firmware. The check below the list says when the set combines: "No conflicts ... Ready to build".
  4. OS version shown: what the unit will show as its OS version: 4 characters on the Digitakt mk1 and the Digitone mk1, 1 to 10 on the Octatrack.
  5. BUILD FIRMWARE: choose where to save the .syx. elekloader builds it, verifies it (see below), and shows its sha256. For the Octatrack it also writes the card file, the .bin beside it.

The details pane shows each mod's description, every change it makes (patch sites, the events it handles, its memory) and what it requires. Profiles save a set of ticked mods. Your library, profiles and the stock file you chose last are kept in %APPDATA%\elekloader (Windows) or ~/.elekloader.

Flash it

Send the .syx to the unit the way Elektron describes for OS updates (How to update your device). For the Digitakt mk1 and the Digitone mk1:

  1. Connect it over USB and open Elektron Transfer.
  2. Select the unit and Connect.
  3. Drag the .syx onto Drop files here.
  4. Press YES on the unit.

Don't turn the unit off until the upgrade is done.

For the Octatrack, from the card (back it up first):

  1. PROJECT > SYSTEM > USB DISK MODE, and copy the .bin to the root of the card.
  2. Eject the card on the computer, then leave USB DISK MODE on the unit.
  3. PROJECT > SYSTEM > OS UPGRADE, and confirm.
  4. When it restarts, power-cycle it once more before judging anything.

Recovery: the bootloader is never changed, so the stock OS file always restores the unit. If a custom OS will not start on a Digitakt mk1 or a Digitone mk1, hold FUNC while powering on for the startup menu, and press TRIG 4 for OS UPGRADE. Then send the stock .syx with Transfer's legacy OS upgrade mode. On the Octatrack: hold FUNC while powering on, press TRIG 3 for MIDI UPGRADE, and send the stock .syx over 5-pin DIN MIDI (USB MIDI does not work for this).

What a build guarantees

The output is refused unless every one of these holds:

  • It is your stock file with only the main OS section changed. The other sections, bootloader included, are byte for byte stock. The header differs only in its 4-character version field; the framing only in its message count.
  • Every message checksum, counter and the content checksum are right, and the container fits the device's flash budget.
  • The main OS unpacks to exactly the patched image, simulated the way the bootloader does it: in place, over its own staged copy.

For the Digitakt mk1, the writer produces the same bytes as elektron-firmware-tool when given the same main OS stream. For the Digitone mk1 (the same file family, with seven sections), it reproduces the stock file from its own main OS stream.

The Octatrack's files are checked the same way: the container header differs only in its 10-character version field, every SysEx message's checksum and the card file's checksum are right, and the .syx and .bin carry the same container. The copy of the bootloader that the OS can re-flash (0x400de1e0-0x400e21e0) must stay stock. The in-place unpack is not simulated there: where its bootloader stages the image is not known yet. From their own main OS stream, the writer reproduces Elektron's .syx and .bin byte for byte.

Mods

Users install mods from their .elemod files. docs/FORMAT.md describes both kinds:

  • format 1: a whole custom build as one file;
  • format 2: separate, linkable mods. A core mod provides a hook bus; other mods subscribe to its events and add entries to each other's tables. The loader's linker places them, resolves their symbols and checks them.

Every set of format-2 mods needs the core mod for its device. The Windows and macOS apps have them built in, and each release carries them: one source, mods/core/core.s, built with each device's addresses (mods/core for the Digitakt mk1, mods/core-dn1 for the Digitone mk1). Each mod.json gives the addresses of every OS it supports (its os, and its ports): the stock file you build with picks them. The Octatrack's, mods/core-ot, is only the boot copier, with no hook bus: it reserves RAM for mods and copies their code there. To build one yourself, use the SDK (below):

python -m elekloader.sdk.build mods/core --stock Digitakt_OS1.54.syx                          # the Digitakt mk1's (or 1.53)
python -m elekloader.sdk.build mods/core-dn1 --stock Digitone_and_Digitone_Keys_OS1.44.syx   # the Digitone mk1's (or 1.43)
python -m elekloader.sdk.build mods/core-ot --stock OCTATRACK_OS1.40C.syx                    # the Octatrack's

Files from before version 0.2 used the .dtmod extension; they still load.

Adapting your mod to elekloader

See docs/ADAPTING.md: the path to take, the rules, each command with the output it should print, a table from every refusal to its fix, and a definition of done. Coding agents: start with AGENTS.md.

The tools, in brief:

python -m elekloader.sdk.build examples/hello-marker --stock Digitakt_OS1.53.syx   # sources -> .elemod
python -m elekloader.lint my-mod-1.0.elemod --stock Digitakt_OS1.53.syx --with core-2.1.elemod
python -m elekloader.mkmod ...                                                      # a whole build -> .elemod
python -m elekloader.sdk.octabam --octabam octabam --stock OCTATRACK_OS1.40C.syx    # octabam modules -> .elemod

For the Octatrack, elekloader.sdk.octabam converts sambanks/octabam's ColdFire modules into linkable mods. It checks each one against octabam's own account of its bytes. See docs/ADAPTING.md, section 4b.

examples/hello-marker/ is a complete mod to start from. It is one C function on the draw event, and it puts a small square in the corner of every screen. Building code needs the device's cross toolchain; for the Digitakt mk1 that is m68k binutils and gcc.

The Windows app

packaging/build_windows.py --core core-2.1.elemod [core-dn1-2.0a.elemod ...] builds elekloader.exe with PyInstaller (packaging/requirements-build.txt). The exe carries the cores in elekloader/bundled. The script checks the exe with its --selftest (the version, Tk, the built-in cores and their hashes, the devices it supports), then writes elekloader-<version>-windows.exe and SHA256SUMS.txt.

The windows-build workflow (Actions, run by hand with a release's tag) does the same on GitHub's Windows runner. It takes every core*.elemod from that release and attaches the exe and SHA256SUMS.txt to it. core is built where the stock OS file is and attached to the release first. No firmware reaches the workflow.

The macOS app

packaging/build_macos.py --core core-2.1.elemod [...] builds elekloader.app the same way, universal2 (Apple silicon and Intel; it needs a universal2 Python, such as python.org's). With --identity (a Developer ID Application certificate in your keychain) every binary in it is signed with the hardened runtime; without, it is signed ad hoc, for trying on your own Mac. It runs the app's --selftest as it will ship, signed, then writes elekloader-<version>-macos.dmg and SHA256SUMS.txt. --notarize has Apple notarize the app and the .dmg and staples both, with an App Store Connect API key in NOTARY_KEY (the .p8 file), NOTARY_KEY_ID and NOTARY_ISSUER.

The macos-build workflow (Actions, run by hand with a release's tag, like windows-build) does all of that on GitHub's macOS runner and attaches the .dmg to the release, adding its line to SHA256SUMS.txt. With test ticked, it builds the branch it is run on with the given release's cores, signs, notarizes and self-tests it the same way, and keeps the .dmg as the run's artifact instead of attaching it: a check of the signing before a release. It needs these repository secrets:

secret what
MACOS_CERTIFICATE the Developer ID Application certificate with its private key, exported from Keychain Access as a .p12, base64-encoded
MACOS_CERTIFICATE_PASSWORD the password the .p12 was exported with
NOTARY_KEY an App Store Connect API key's AuthKey_<id>.p8, its text as it is
NOTARY_KEY_ID that key's ID
NOTARY_ISSUER the Issuer ID shown above the keys in App Store Connect

Tests

python tests/test_units.py        # needs nothing
ELEKLOADER_STOCK=Digitakt_OS1.53.syx ELEKLOADER_MODS=path/to/mods python tests/test_link.py
ELEKLOADER_STOCK=... ELEKLOADER_STOCK_154=Digitakt_OS1.54.syx ELEKLOADER_MODS=... python tests/test_sdk.py   # the example needs the cross compiler
ELEKLOADER_RELEASES=folder/of/stock/files python tests/test_releases.py   # every known release, and its cores
ELEKLOADER_STOCK=... ELEKLOADER_BUNDLE=bundle.elemod ELEKLOADER_CTOOL_SYX=its-build.syx python tests/test_patcher.py
ELEKLOADER_OT_SYX=OCTATRACK_OS1.40C.syx ELEKLOADER_OT_BIN=OCTATRACK_OS1.40C.bin python tests/test_octatrack.py
ELEKLOADER_OT_SYX=... ELEKLOADER_OCTABAM=path/to/octabam python tests/test_octabam.py   # octabam optional
ELEKLOADER_DN_SYX=Digitone_and_Digitone_Keys_OS1.43.syx python tests/test_digitone.py
ELEKLOADER_STOCK=... ELEKLOADER_STOCK_154=... ELEKLOADER_OT_SYX=... ELEKLOADER_MODS=... python tests/test_gui.py   # the window, hidden (Tk)
node tests/test_web.mjs build/site   # the web page's engine, in Pyodide (packaging/build_web.py first)

A test whose input files are not given is skipped, not passed. Firmware files never go in this repository.

Licence

GPL-2.0-or-later. See LICENSE, and NOTICE for the code that comes from digikit and for the credits. elekloader is not affiliated with Elektron. Flashing custom firmware is at your own risk.