Commands¶
Canonical commands for MatchPatch development. Run from the repository root.
Environment¶
Create or update the shared WSL development environment:
scripts/sync-wsl.sh
Activate it when running commands interactively:
source "$HOME/.local/share/matchpatch/.venv-wsl/bin/activate"
Create or update the native Windows environment used for hardware audio/MIDI work from WSL:
scripts/sync-windows-from-wsl.sh
The Windows environment is stored in .venv-windows. The WSL environment is
stored under ${XDG_DATA_HOME:-$HOME/.local/share}/matchpatch/.venv-wsl.
Test¶
Use the shared WSL pytest binary:
$HOME/.local/share/matchpatch/.venv-wsl/bin/pytest
Run a focused test:
$HOME/.local/share/matchpatch/.venv-wsl/bin/pytest tests/test_measure.py::test_loopback_backend_writes_compatible_csv
Run GUI tests:
scripts/test-gui.sh
Run a focused GUI test:
scripts/test-gui.sh tests/test_gui.py::test_loaded_file_updates_window_title_and_save_as_state
Do not rely on bare pytest; it may not be on PATH. Avoid uv run pytest
for local work when the project-local .venv is stale or incomplete.
Quality¶
After syncing and activating the WSL env:
ruff check .
ruff format --check .
ty check
$HOME/.local/share/matchpatch/.venv-wsl/bin/pytest
Install the local Git hooks, including the Conventional Commit commit-msg
hook and the pre-push quality suite:
pre-commit install --install-hooks
pre-commit run --all-files --hook-stage pre-push
If hooks were already installed before commit-msg was added, reinstall all
configured hook types:
pre-commit install --hook-type pre-commit --hook-type commit-msg --hook-type pre-push --install-hooks
Commit messages must use Conventional Commits:
feat(gui): add snapshot diff selector
fix: preserve adjusted setlist output path
chore(release): v0.2.0
CI runs equivalent uv run --frozen --no-default-groups --group wsl commands on
Linux, Windows, and WSL for Python 3.12, 3.13, and 3.14.
Run The CLI¶
Show environment:
matchpatch --environment
List supported processor profiles:
matchpatch --devices
Export default config:
matchpatch --export-default-config ~/.config/matchpatch/config.toml
Installed Windows builds automatically look first in the roaming profile:
MatchPatch.exe --cli --export-default-config "$env:APPDATA\MatchPatch\config.toml"
When --config is omitted, MatchPatch searches for config files in this order:
%APPDATA%\MatchPatch\config.toml, then
%USERPROFILE%\.config\matchpatch\config.toml on Windows; on Linux/WSL/macOS,
$XDG_CONFIG_HOME/matchpatch/config.toml when XDG_CONFIG_HOME is set,
otherwise ~/.config/matchpatch/config.toml.
Normalize without hardware:
matchpatch normalize --device helix --backend loopback -i setlist.hls -o setlist_adjusted.hls -S 01A --keep-temp
Normalize with simulated hardware:
matchpatch normalize --device helix --backend simulated -i setlist.hls -o setlist_adjusted.hls -S 01A,01B --keep-temp
Guided hardware workflow:
matchpatch normalize --device helix -a -i setlist.hls
Single .hlx preset measurement requires one temporary Helix slot:
matchpatch normalize --device helix -a -i Song.hlx -S 12A
Select only presets changed relative to an earlier setlist:
matchpatch normalize --device helix -a -i current.hls --diff-input previous.hls
Native Measurement Worker¶
From WSL, list native Windows audio/MIDI devices:
scripts/measure-windows-from-wsl.sh devices
Run a direct loopback measurement:
python -m matchpatch.measure measure --device helix --backend loopback --preset-ids 1,6 --csv /tmp/lufs_analysis.csv --reference-di audio/reference-di/DI_Strandberg_Boden_Fusion_Bridge_Humbucker.wav
Run the Windows worker from WSL:
scripts/measure-windows-from-wsl.sh measure --device helix --backend hardware --preset-ids 1,6 --csv "$(wslpath -w /tmp/lufs_analysis.csv)" --reference-di "$(wslpath -w audio/reference-di/DI_Strandberg_Boden_Fusion_Bridge_Humbucker.wav)"
Check hardware availability:
scripts/measure-windows-from-wsl.sh check-hardware --device helix
GUI¶
Install GUI dependencies into the WSL env:
scripts/sync-wsl.sh --extra gui
Launch:
matchpatch-gui
The GUI starts with the configured backend and can run loopback/simulated flows without Helix hardware. Hardware mode requires the native Windows environment and visible audio/MIDI endpoints.
Legacy Helix Utilities¶
Run from the repository root:
python3 Python/preset_handling.py --help
python3 Python/decrypt_hls.py --help
python3 Python/encrypt_hls.py --help
Useful integrated operations:
python3 Python/preset_handling.py -i setlist.hls -o setlist_measurement.hls --measurement
python3 Python/preset_handling.py -i setlist.hls --list-presets
python3 Python/preset_handling.py -i current.hls --diff-presets previous.hls
Build¶
Build wheel and source distribution:
uv build --no-sources
Smoke-test built artifacts:
uv run --isolated --no-project --with dist/*.whl python -c "import matchpatch"
uv run --isolated --no-project --with dist/*.tar.gz python -c "import matchpatch"
Packaging¶
The checked-in Windows packaging pipeline builds a frozen application payload with PyInstaller, then packages that payload with Inno Setup 6.
Prerequisites:
A native Windows checkout, or WSL with the Windows mirror workflow.
uv.Inno Setup 6, with
ISCC.exeonPATH, installed in the default location, or referenced byINNO_SETUP_ISCC.
Build and test the installer from WSL:
scripts/test-windows-installer-from-wsl.sh
Build only the installer from WSL:
scripts/build-windows-installer-from-wsl.sh
Build and test from a native Windows checkout:
scripts\test-windows-installer.cmd
Build only from a native Windows checkout:
scripts\build-windows-installer.cmd
Build only the frozen payload:
scripts\build-windows-payload.cmd
The default WSL mirror lives at /mnt/c/src/MatchPatch-windows. Override it
with MATCHPATCH_WINDOWS_WORKDIR if your Windows checkout lives elsewhere.
Generated outputs:
Payload:
build/windows-payload/MatchPatch/Payload manifest:
build/windows-payload/MatchPatch/build-info.jsonInstaller:
dist/installer/MatchPatch-Setup-<version>.exeOffline help staged beside the executable:
docs_html/
Run smoke tests against an existing installer artifact:
scripts\test-windows-installer.cmd --reuse-artifact
scripts\test-windows-installer.cmd --installer C:\path\to\MatchPatch-Setup-0.1.0.exe
Add --gui-smoke to initialize the GUI in non-interactive smoke mode as part
of the payload and installed-app checks.
The smoke tests verify that MatchPatch.exe, bundled docs_html/index.html,
installer artwork, and build-info.json exist; that
build-info.json reports the expected version; that
MatchPatch.exe --cli --version starts cleanly; and that the
installer can install and uninstall silently.
Troubleshooting:
If a script reports a UNC path problem, run from a native Windows path or use the WSL wrapper so the project is mirrored to a Windows filesystem.
If
ISCC.exeis missing, install Inno Setup 6, add it toPATH, or setINNO_SETUP_ISCCto the full compiler path.If the GUI fails with Qt or PySide6 plugin startup errors, rebuild the payload with
scripts\build-windows-payload.cmdso PyInstaller can restage Qt plugins and runtime files.Antivirus warnings can happen while testing the unsigned installer. Verify the artifact came from your local build or GitHub Actions before allowing it.
Brand assets for app packaging live in docs/assets/.
Stage the offline documentation payload manually with:
scripts/stage-installer-docs.sh <installer-payload-dir>
The script builds docs_html/, copies it to
<installer-payload-dir>/docs_html, and verifies that the installer payload has
the docs index, quick start, workflow pages, concept pages, and Sphinx static
assets. Installers should place that docs_html/ directory beside the GUI
executable so matchpatch.gui.help.local_docs_root() can resolve local
file:// help URLs.
Sync the opt-in Windows installer build environment from a native Windows checkout with:
uv sync --locked --no-default-groups --group windows --group docs --group installer --extra gui
Inno Setup is intentionally not a Python dependency. Install Inno Setup on the Windows host or provide it in CI before running installer packaging scripts.
Docs¶
Build the local Sphinx HTML documentation with:
scripts/build-docs.sh
The wrapper cleans docs_html/, runs Sphinx in strict mode, and writes the
generated offline help bundle back to docs_html/.
Suggested checks for docs-only changes:
scripts/build-docs.sh
ruff format --check .
git diff --check
Release¶
Release automation is tag-driven and publishes to PyPI from GitHub Actions.
Update
project.versioninpyproject.toml.Commit the version change.
Tag with
v<version>matchingpyproject.toml.Push the tag.
git tag v0.1.0
git push origin v0.1.0
The release workflow verifies the tag/version match, runs uv build --no-sources, smoke-tests the wheel and source distribution, builds and uploads
the offline docs artifact, publishes to PyPI with trusted publishing, and runs a
separate Windows job that builds, smoke-tests, uploads, and attaches
MatchPatch-Setup-<version>.exe to the GitHub Release.