fluxctl is a modular toolkit for inspecting and converting floppy disk flux captures. It supports decoding flux streams, reconstructing sectors, quality control, visualization, extraction, and exporting to standard image formats.
Until the packaging branch is merged to main, clone or switch to the branch
before running the source installer:
git clone -b codex/packaging-distribution https://github.com/GeoKM/fluxctl.git
cd fluxctl
python3 scripts/install_fluxctl.py --yes --greaseweazle --clone-greaseweazle --clone-hxcfe --build-hxcfeAfter the packaging branch is merged to main, the easiest source-checkout
install becomes:
git clone https://github.com/GeoKM/fluxctl.git
cd fluxctl
python3 scripts/install_fluxctl.py --yes --greaseweazle --clone-greaseweazle --clone-hxcfe --build-hxcfe
.venv/bin/fluxctl doctorOn Windows PowerShell, use the Python launcher and Windows script paths:
New Windows setup? Start with the Windows prerequisites and installation guide for required downloads, optional build tools, architecture selection, and verification steps.
git clone -b codex/packaging-distribution https://github.com/GeoKM/fluxctl.git
cd fluxctl
py -3 scripts\install_fluxctl.py --yes --greaseweazle --clone-greaseweazle --clone-hxcfe --build-hxcfe --build-native
.venv\Scripts\fluxctl.exe doctor
.venv\Scripts\fluxctl.exe --help
.venv\Scripts\fluxctl-studio.exeOn Windows, Fluxctl itself needs Git and Python. Optional helper builds need extra native build tools:
- Greaseweazle: install Microsoft C++ Build Tools 14.0 or newer with the "Desktop development with C++" workload.
- HxCFE: install a GNU Make/GCC environment such as MSYS2/MinGW64, or use a
prebuilt
hxcfe.exeand pass--hxcfe C:\path\to\hxcfe.exe. - Rust native acceleration: install Rust from
https://rustup.rsand Microsoft C++ Build Tools 14.0 or newer with the "Desktop development with C++" workload so the MSVC linkerlink.exeis available.--build-nativedetects the virtual environment's Python architecture and selects the matching Rust target. This matters on Windows ARM64, where an x64 Python may run under emulation and cannot load an ARM64 DLL.
This creates .venv, installs fluxctl and Fluxctl Studio, offers optional
Greaseweazle support, clones/builds optional HxCFE support, and prints the
installed command paths. Run .venv/bin/fluxctl --help to explore available
targets.
For a minimal manual install instead:
python3 -m venv .venv
.venv/bin/python -m pip install --upgrade pip
.venv/bin/python -m pip install -e .For an interactive source-checkout install that can also offer GUI and optional Greaseweazle/HxCFE setup checks, run:
python3 scripts/install_fluxctl.py- info: inspect SCP headers and inferred geometry.
- doctor: check the local installation and optional helper integrations.
- probe: detect encoding, layout, and filesystem (where detectable) for SCP, IMD, TRS-80
.dsk/.dmk, and flat images. - compare: hash + byte diff two images; SCP inputs are decoded first.
- roundtrip: convert through an intermediate format and verify decoded-sector hashes after each leg.
- qc: generate quality control reports (JSON or text).
- visualize: render ASCII or SVG disk maps.
- extract: detect filesystems and extract files or raw sectors.
- convert: export to raw, IMD, ADF, D64, D71, D81, and G64 images.
- sectors/dump/patch: per-track listing, hex dump, and simple patching helpers.
- studio: optional desktop GUI for guided and advanced workflows.
- Encodings: MFM, FM, GCR (Commodore) via plugin registry.
- Filesystems detected: FAT12, CBM DOS, CP/M (C64 CP/M 2.2, C128 CP/M 3.0, Osborne/Kaypro/Tandy variants), TRSDOS 1.3, LDOS/TRSDOS 6, NEWDOS/80, Amiga OFS/FFS, RT-11 (RX02), Displaywriter probe; raw sector dumps always supported.
- Filesystem listing, extraction, export, and copy-only mutation support varies by format. See the filesystem capability matrix for current limitations.
# Quick identification
fluxctl doctor
fluxctl info disk.scp
fluxctl probe disk.scp
# Compare two images (SCP decoded on the fly)
fluxctl compare a.scp b.img --json-out diff.json
fluxctl compare before.img after.img
# Verify conversion losslessness through decoded sector hashes. Round-trip
# checks compare reconstructed sector bytes, not raw flux timing bytes.
fluxctl roundtrip amiga.scp --layout amiga_mfm_880k --to adf --json-out roundtrip.json
fluxctl roundtrip disk.adf --to raw --back-to adf --work-dir /tmp/fluxctl-roundtrip
# Planned once SCP export exists:
# fluxctl roundtrip disk.adf --to scp --back-to adf
# fluxctl roundtrip disk.img --layout ibm_mfm_720k --to scp --back-to raw
# Quality reports and maps
fluxctl qc disk.scp --json-out qc.json
fluxctl visualize disk.scp --format ascii --out map.txt
# Export / convert
fluxctl convert disk.scp --to raw --out disk.img
fluxctl convert disk.scp --to raw --out disk.img --layout ibm_mfm_720k
fluxctl convert disk.img --to imd --out disk.imd --layout ibm_mfm_720k
fluxctl convert trs80.dsk --to imd --out trs80.imd
fluxctl convert trs80.dmk --to imd --out trs80.imd
fluxctl convert c64.scp --to d64 --out disk.d64
fluxctl convert c64.scp --to g64 --out disk.g64 --layout commodore_gcr_1541_170k
fluxctl convert c128.scp --to d71 --out disk.d71 --layout commodore_gcr_1571_341k
fluxctl convert 1581.scp --to d81 --out disk.d81 --layout commodore_mfm_1581_800k
fluxctl convert disk.d81 --to raw --out disk.img
fluxctl convert disk.img --to raw --out copy.img
# Extraction
fluxctl extract disk.img --list
fluxctl extract disk.img --path FILE.TXT --out output.bin
fluxctl extract disk.scp --layout ibm_mfm_720k --path README.TXT --out readme.bin
# Per-track inspection
fluxctl sectors disk.scp --track 0 --head 0 --encoding mfm
fluxctl dump disk.scp --layout ibm_mfm_720k --track 0 --side 0 --sector 1
# Patch one full sector and export a raw image
fluxctl patch disk.scp --layout ibm_mfm_720k --write-sector 0:0:1:DEADBEEF... --out patched.imgUse fluxctl doctor when a conversion, decode, or optional helper path behaves
unexpectedly. It reports:
- Python and fluxctl versions.
- Loaded layouts, decoders, exporters, and filesystem readers.
- Whether optional Rust native decoder acceleration is enabled, disabled, or not built yet.
- Whether the optional Greaseweazle Python package can be imported.
- Whether
hxcfeis available onPATH, at a supplied--hxcfepath, or in a sibling../HxCFloppyEmulatorcheckout built by the installer.
Examples:
fluxctl doctor
fluxctl doctor --json
fluxctl doctor --hxcfe ~/src/HxCFloppyEmulator/HxCFloppyEmulator_cmdline/build/hxcfeWarnings are informational for optional features. A missing native library only
means fluxctl will use the pure-Python decoder path. A failed hxcfe check only
matters when you explicitly want HxC-assisted hints.
Fluxctl Studio is an optional desktop interface for the same core operations as the CLI. It is designed around two workflows:
- Simple Mode: open an image, run doctor/probe/QC, render a disk map, list filesystem files, inspect file/sector hex, export files, replace supported files into a new image copy, create common blank disk images, and convert common output formats with fewer choices.
- Advanced Mode: expose layout, encoding, track/head/sector, compare, sector listing, hex dump, conversion, and provenance inspection controls.
Install the GUI dependency and launch it:
.venv/bin/python -m pip install -e ".[gui]"
.venv/bin/fluxctl-studioThe GUI uses the same fluxctl package and CLI command paths as terminal workflows. Outputs such as converted images, QC reports, and provenance sidecars therefore follow the same behavior documented above.
For SCP inputs, convert auto-detects the likely layout when --layout is not
provided. Pass --layout when you want to force a specific interpretation or
when a damaged/ambiguous capture cannot be identified confidently.
File replacement is intentionally conservative. Studio currently supports
replacement for FAT12 files in flat .img images only, and always writes a new
image copy instead of modifying the original image. FAT12 replacements may grow
the selected file by allocating free clusters in the copied image. Replacement
for other filesystems or image containers that would require format-specific
sector rewrites is rejected until dedicated writers exist.
Studio also supports FAT12 .img file manipulation into new image copies:
delete a file or empty directory, import a file, recursively import a directory
tree, and create an empty directory. FAT12 import and directory creation
currently require 8.3-compatible ASCII names and reject overwriting existing
entries.
CBM DOS .d64 and .d71 images also support root-level PRG file import into a
new image copy. CBM DOS import currently uses ASCII names up to 16 characters
and does not overwrite existing entries.
For CBM DOS sector hex and dump controls, Studio accepts Commodore logical track
numbers: the 1541/1571 BAM is entered as track 18, head 0, sector 0.
- D64: reconstructed 256-byte logical sectors written to a flat image. This is convenient for filesystem access but loses per-track GCR details and any copy-protection data.
- G64: preserves the decoded GCR nibble stream for each track in a half-track container. This format retains gaps and sync marks for better fidelity in emulators, but currently derives half-tracks from full-track captures only (no separate half-track decoding yet).
- Execute
.venv/bin/python -m pytestafter activating the venv to cover CLI helpers, decoding, exporters, and filesystems. - The repository also includes
tests/fixtureswith annotated samples so you can run targeted commands against known media. - For full CLI validation across SCP fixtures (with longer GCR timeouts), run
scripts/fixture_cli_smoke.py.
Fluxctl is licensed under the Apache License, Version 2.0. See LICENSE for the full license text.
On macOS, optional helper builds need Apple's Command Line Tools for clang,
make, and system headers:
xcode-select --install
Full Xcode is usually not required.
Fluxctl can fall back to Greaseweazle’s Amiga and IBM FM/MFM codecs for higher-fidelity PLL decoding. This is optional; when missing, fluxctl uses its own PLL/parser.
Steps:
- Get Fluxctl's Greaseweazle support dependencies:
.venv/bin/pip install -e ".[greaseweazle]" - Install the actual Greaseweazle Python package into the same venv. The
source-checkout installer can do this automatically if a sibling checkout
exists, or can clone it with
--clone-greaseweazle; otherwise clone Greaseweazle alongside fluxctl and install it editable:git clone https://github.com/keirf/Greaseweazle.git ../greaseweazle .venv/bin/pip install -e ../greaseweazle
No configuration is required; fluxctl will auto-detect the import at runtime when present.
HxCFE can provide layout hints and ADF conversions for Amiga and other formats.
Steps:
- Clone and build
hxcfe(the CLI from HxCFloppyEmulator). The source-checkout installer can clone it with--clone-hxcfeand attempt the Makefile build with--build-hxcfe; manually:git clone https://github.com/jfdelnero/HxCFloppyEmulator.git ../HxCFloppyEmulator make -C ../HxCFloppyEmulator/build HxCFloppyEmulator_cmdline - Point fluxctl at the binary when running commands that accept
--hxcfe, e.g.:fluxctl qc disk.scp --layout amiga_mfm_880k --hxcfe ~/src/HxCFloppyEmulator/HxCFloppyEmulator_cmdline/build/hxcfe fluxctl probe disk.scp --hxcfe /path/to/hxcfe
HxCFE is optional; when omitted, fluxctl uses its own detectors.
Fluxctl can load an optional Rust native library for hot flux-to-bitcell decoder loops. The Python implementation remains the fallback when the library is not built.
Build the native library from the repository root:
cargo build --manifest-path native/fluxctl_native/Cargo.toml --release
On Windows, the safer source-install route is
py -3 scripts\install_fluxctl.py --build-native; it builds for the Python
process architecture. For a manual build, use the target printed by
fluxctl doctor, for example:
rustup target add x86_64-pc-windows-msvc
cargo build --manifest-path native\fluxctl_native\Cargo.toml --release --target x86_64-pc-windows-msvcIf cargo is missing, install Rust first. The standard cross-platform path is:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Then open a new shell, or run source "$HOME/.cargo/env", and retry the
cargo build command. On Debian/Ubuntu packaged Rust can also be installed with
sudo apt install cargo rustc, but rustup usually provides a newer toolchain.
On Windows, install Rust from https://rustup.rs and Microsoft C++ Build Tools
14.0 or newer with the "Desktop development with C++" workload. If cargo
reports link.exe is missing, run the build from Developer PowerShell for
Visual Studio or a Native Tools command prompt so the MSVC linker is on PATH.
Use the x64 Native Tools prompt for x86_64-pc-windows-msvc, or the ARM64
Native Tools prompt for aarch64-pc-windows-msvc. If the linker reports
LNK4272, the prompt and Rust target do not match. For a native ARM64 build:
"C:\Program Files (x86)\Microsoft Visual Studio\18\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" arm64
Fluxctl auto-detects the resulting library under native/fluxctl_native/target.
Set FLUXCTL_NATIVE_PATH=/path/to/libfluxctl_native.dylib (or .so/.dll) to
override the lookup path. Set FLUXCTL_DISABLE_NATIVE=1 to force the pure
Python fallback.
If a built library still shows as unavailable, fluxctl doctor reports the
native load error. On Windows, errors such as "not a valid Win32 application" or
LNK4272 usually mean the Python architecture, Rust target, and Visual Studio
Native Tools prompt do not all match. Do not use platform.machine() to choose
the DLL architecture on Windows ARM64: it may report the host (ARM64) for an
emulated x64 Python. Fluxctl uses Python's win-amd64/win-arm64 platform tag
and reads the DLL's PE header directly.
See AGENTS.md for coding standards, workflows, and review expectations. See docs/packaging.md for wheel, source distribution, and standalone GUI/CLI packaging notes. See docs/windows-prerequisites.md for the Windows software checklist and installation walkthrough.
Commands that create output files write provenance sidecars by default:
convert --out disk.imgwritesdisk.img.provenance.json.qc --json-out qc.jsonor--text-out qc.txtwrites a sidecar for the first report path.visualize --out map.txtwritesmap.txt.provenance.json.extract --out file.binwritesfile.bin.provenance.json.compare --json-out diff.jsonwritesdiff.json.provenance.json.patch --out patched.imgwritespatched.img.provenance.jsonand a separate patch log.
Use --prov-out custom.provenance.json on commands that support it to choose
the sidecar path. Terminal-only commands such as info, probe, sectors,
dump, and extract --list print results but do not create sidecars unless a
file output option is used. Provenance records capture tool version, inputs,
outputs, hashes, parameters, timestamps, and decoder/exporter identifiers so
artefacts can be verified later.