Skip to content

HLX Generator: AI preset builder, UI overhaul, 250-test suite - #2

Open
edonahue wants to merge 58 commits into
mainfrom
claude/hx-stomp-midi-interface-imC1V
Open

HLX Generator: AI preset builder, UI overhaul, 250-test suite#2
edonahue wants to merge 58 commits into
mainfrom
claude/hx-stomp-midi-interface-imC1V

Conversation

@edonahue

Copy link
Copy Markdown
Owner

Summary

  • AI Preset Generation — complete hlx_builder.py pipeline: LLM prompt, fuzzy model-ID recovery, param clamping, .hlx file construction. Includes hx_models.py (84+ verified amp/cab/effect models), model_aliases.csv, Manual Mode (copy prompt to any AI chatbot, import response), and Preset Catalog browser.
  • UI overhaulicon_manager.py Phosphor icon loader with lru_cache; full icon + typography modernisation across all dialogs; Line 6-accurate category colors (Amp=red, Delay=green, Distortion=amber, etc.); genre tags (12 genres, colored chips); block-card tooltips, subcategory labels, and key-param captions; app icon (512×512) + .desktop file + --install-desktop CLI flag.
  • LLM quality improvements — artist alias matching, ChVol / Master / Drive param constraints, tone guide in system prompt, genre field in LLM response, signal-order validation, per-block parameter explanations.
  • Test suite — 250 tests across four files (test_hlx_builder, test_tone_manager, test_midi_and_utils, test_icon_manager); CI workflow updated to run all four.
  • Project rename — display name changed to HLX Generator throughout (window title, README, docs, argparse). System identifiers (hxstomp, ~/.hxstomp/) unchanged for backward compatibility.

What is NOT changing

  • MIDI Soundboard is fully retained — all CC logic, Live Controls, Tap Tempo, Looper, Tuner are intact.
  • ~/.hxstomp/ config and preset storage path is unchanged.
  • hxstomp system identifier (.desktop file, WMClass, icon name) is unchanged.

Test plan

  • python -m unittest test_hlx_builder test_tone_manager test_midi_and_utils test_icon_manager -v → 250 tests pass
  • CI passes on push
  • python main.py --mock-midi — app opens on HLX Generator tab
  • Describe a tone → Generate Preset → genre chip + colored block cards visible
  • Save .hlx → appears in Preset Catalog
  • MIDI Soundboard tab — connect dialog, tone cards, Live Controls all functional

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn

claude added 30 commits March 25, 2026 22:12
midi_interface.py — full rewrite based on official Line 6 docs:

Bug fixes:
- Tuner (CC 68) is a TOGGLE not absolute on/off: replaced set_tuner(bool)
  with toggle_tuner() that tracks internal state; set_tuner(bool) kept as
  a smart wrapper that only sends when state differs
- Footswitch numbering corrected: CC54 = FS7 (not FS6); Helix numbering
  skips FS6. Renamed CC_FS6_BYPASS → CC_FS7, added CC_FS8–CC_FS11.
  set_effect_bypass() replaced with press_footswitch()/release_footswitch()
  with clear docs that these TOGGLE the assigned block (not absolute state)

New CC coverage (all reserved HX Stomp CCs now implemented):
- CC 1/2   : set_exp1(), set_exp2() — expression pedal position (0–127)
- CC 59    : set_exp_toe() — EXP toe switch engage/release
- CC 60–67 : full looper transport — looper_record(), looper_overdub(),
             looper_play(), looper_stop(), looper_play_once(),
             looper_undo_redo(), looper_reverse(), looper_half_speed(),
             looper_enabled()
- CC 64    : tap_tempo() — single tap (any value fires once)
- CC 69=8  : next_snapshot() — SNAPSHOT_NEXT constant
- CC 69=9  : prev_snapshot() — SNAPSHOT_PREV constant

Added "helix" to find_hx_port() keyword list.
Added _FS_CC dict for footswitch→CC lookup; validates fs number with
meaningful error (lists valid values, notes FS6 absence).

soundboard_ui.py:
- _toggle_tuner() now delegates to self._midi.toggle_tuner() directly,
  removing the redundant internal _tuner_state tracking

main.py — MockHXStompMidi updated to mirror full new API:
- toggle_tuner() / set_tuner() with internal state tracking
- press_footswitch() / release_footswitch()
- set_exp1/2/toe(), tap_tempo()
- Full looper suite
- next_snapshot() / prev_snapshot()
- select_snapshot() labels 8/9 as "next"/"previous" in output

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
Feature 1 — LLM Tone Generation (llm_generator.py):
- Multi-provider architecture: Anthropic (default), OpenAI, Ollama, Gemini
- LLMProvider ABC with pluggable complete(system, user) → str interface
- Config persisted to ~/.hxstomp/config.json per provider
- generate_tone() parses JSON from LLM with one retry on parse failure
- GenerateToneDialog: provider dropdown, ⚙ Configure… per provider, async threading
- ProviderConfigDialog: API key / model / base URL per provider
- ✨ Generate toolbar button + Tones → ✨ Generate Tone… menu entry
- --no-llm, --api-key, --llm-provider CLI flags in main.py

Feature 2 — Live Control Panel (soundboard_ui.py):
- LiveControlPanel(CTkFrame): snapshot nav, tap tempo + BPM, looper transport
- Tap tempo: 60/mean(last 8 intervals), resets after 4 s silence, sends CC each tap
- Looper: Record (red), Play (green), Stop, Overdub (orange), Once, Undo,
  Reverse toggle, Half Speed toggle — with state-aware button highlighting
- Collapsible via ⚡ Live toolbar button or View → ⚡ Live Controls menu checkbutton
- Non-modal MIDI guard: shows status bar message instead of dialog

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
Three gaps fixed in GenerateToneDialog:

1. Proactive key warning: amber label appears immediately on dialog open
   when the selected provider has no API key configured (checks both
   ~/.hxstomp/config.json and the provider's env var). Clears instantly
   after ProviderConfigDialog is saved. Ollama never shows a warning.
   Requires new env_var class attribute on each provider.

2. Active model readout: dim "using claude-haiku-4-5" label added next
   to the provider dropdown. Updates on provider switch and after
   Configure dialog closes.

3. Scope hint: static two-line dim text below the description area
   explains that AI generates name/color/category/snapshot only, and
   that the user sets the preset number in the next step because preset
   slots are rig-specific.

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
README.md (full rewrite):
- Installation with virtualenv, Linux system lib notes
- MIDI connection walkthrough including channel matching
- Tone grid guide: fields, preset numbering, presets.json format
- AI tone generation: step-by-step, provider table, env var method
- Live Controls: snapshot nav, tap tempo, looper transport table
- Tuner toggle behavior note (hardware toggle, state tracking caveat)
- Keyboard shortcuts, full CLI reference with examples
- Config file schema reference
- MIDI overview table with links to full reference

docs/MIDI_REFERENCE.md (new):
- Complete CC map table (CC0–CC69)
- Preset display-label to PC number conversion formula + table
- Setlist / Bank LSB mapping
- Snapshot CC69 value table (0-7 direct, 8/9 relative)
- Tuner toggle semantics
- Footswitch emulation with FS6-skip explanation
- Looper CC semantics (threshold on/off model, not toggle)
- Recommended looper sequences
- Python API quick-reference

docs/LLM_PROVIDERS.md (new):
- What AI generates vs what user provides
- Provider comparison table (speed, cost, privacy)
- Per-provider: package install, key acquisition, 3 setup options,
  model selection, alternatives
- Ollama: install, pull, serve, remote host config
- Switching providers in-app and via CLI
- Config file schema with all fields and defaults
- Troubleshooting section for common errors

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- Rename "AI Tone Generation" section to "AI-Assisted Preset Labeling"
- Update feature highlight bullet to clarify metadata-only output
- Add "What this feature does NOT do" callout in README AI section
- Add Roadmap section describing planned .hlx preset generation
- Rename toolbar button from "✨ Generate" to "✨ Label Tone"

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
Add the ability to generate complete HX Stomp .hlx preset files from a
plain-English tone description or artist name.

New files:
- hx_models.py: curated catalog of 52 HX Stomp amp/cab/effect model IDs
  with descriptions, default params, and catalog_for_prompt() for LLM injection
- hlx_builder.py: .hlx template construction (build_hlx, save_hlx),
  PresetCatalog for ~/.hxstomp/presets/ management, and
  generate_hlx_preset() core LLM-to-.hlx function
- docs/HLX_GENERATION.md: full user guide (usage, model table, HX Edit
  import steps, tips, troubleshooting)

Modified:
- llm_generator.py: add max_tokens param to all 4 provider complete()
  methods (default=200, .hlx generation uses 1500); add
  GeneratePresetDialog with signal chain strip, per-block explanations,
  design rationale, Save .hlx and Regenerate actions
- soundboard_ui.py: add 📦 Preset toolbar button and
  Tones → Generate Preset (.hlx)… menu item; _generate_preset() handler

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- Feature highlights: add AI preset generation bullet
- Add full "AI Preset Generation (.hlx)" section with usage steps,
  what-gets-generated table, and link to docs/HLX_GENERATION.md
- Update labeling section to reference new preset generator instead
  of roadmap
- Update project structure to include hx_models.py, hlx_builder.py,
  and docs/HLX_GENERATION.md
- Replace Roadmap with forward-looking items (direct loading,
  catalog expansion, snapshot generation)

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
PresetCatalogDialog (llm_generator.py):
- Scrollable list of all generated .hlx presets from
  ~/.hxstomp/presets/catalog.json
- Each row shows preset name, creation date, mini signal-chain strip
  (coloured chips matching GeneratePresetDialog), and design rationale
- Per-row actions: 📂 Show (reveal in file manager), 💾 Export… (copy
  to chosen path), 🗑 remove catalog entry
- Empty state message when no presets exist yet
- Refresh button reloads catalog from disk

Wired into soundboard_ui.py:
- 📋 Catalog toolbar button (after 📦 Preset)
- Tones → 📋 Preset Catalog… menu item
- _open_catalog() handler (no LLM dependency — always available)

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- build_hlx() now accepts optional snapshots_spec list; populates snapshot
  names and per-block bypass states from LLM response instead of generic
  "SNAPSHOT N" defaults with all blocks enabled
- PresetResult dataclass gains a snapshots field (list of name/description/
  block_states dicts)
- generate_hlx_preset() parses the snapshots array from LLM JSON response
  and threads it through to build_hlx() and PresetResult
- GeneratePresetDialog result panel now shows 3 coloured snapshot pills
  (name + one-sentence description) between the signal chain strip and rationale

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
hlx_builder.py
- PresetCatalog.save_preset() now writes snapshots array to catalog.json
  so catalog entries carry snapshot metadata (name, description, block_states)

llm_generator.py
- PresetCatalogDialog._build_row() shows up to 3 coloured snapshot pills
  (blue/purple/green) per preset row; falls back gracefully for older
  entries that have no snapshots key

hx_models.py - 52 → 71 models (+19)
- Amps: Revv Gen Red, Das Benzin, Voltage Queen, Soup Pro, Mail Order Twin,
  Interstate Zed, Divided Duo (+7)
- Cabs: 4x12 Brit Basket, 2x12 Interstate, 1x8 Tweed Champ (+3)
- Distortion: Deranged Master, Pillars OD (+2)
- Modulation: UniVibe, CE-1 Chorus (+2)
- Delay: Cosmos Echo, Reverse Delay (+2)
- Reverb: Octo, Cave, Plateaux (+3)

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
README.md
- Restructured into two clear pillars: Part 1 (MIDI Soundboard) and
  Part 2 (AI Preset Tools), each with its own section hierarchy
- Moved Preset Catalog into Part 2 as its own ### section
- Updated What Gets Generated table to include snapshots
- Fixed: GeneratePresetDialog note no longer claims snapshots are not generated
- Updated project structure model count 52 → 71
- Removed Snapshot Generation from Roadmap (shipped); added Snapshot
  Parameter Control as the forward-looking item
- Unified formatting: consistent tables, code blocks, tip callouts

soundboard_ui.py
- Added _render_empty_state() method: shown when no tones exist
- Lists four getting-started steps with action name + description
  (Add Tone, Label Tone, Generate Preset, Connect MIDI)
- Consistent dark card rows matching the rest of the UI palette

llm_generator.py
- GeneratePresetDialog hint updated to mention three named snapshots
- GenerateToneDialog hint updated to clarify labeling scope and cross-
  reference 📦 Preset for users who want full .hlx generation

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
soundboard_ui.py
- Add _BG_MENU = "#2b2b2b" constant; replace 7 hardcoded bg strings in
  all tk.Menu and right-click context menu constructors
- Standardize toolbar button widths: left group (Add/Edit/Remove/Reload)
  all 90px; AI group (Label Tone/Preset/Catalog) all 105px — eliminates
  the previous ragged 90/90/100/90 | 115/100/95 layout
- Empty-state subtitle: #555555 → _TEXT_DIM (#888888) for legibility on
  dark background

llm_generator.py
- Extract _SNAP_COLORS as module-level tuple constant; remove two local
  list definitions in _build_result_panel() and _build_row() (DRY fix)
- GeneratePresetDialog: resizable(True, False) → resizable(False, False)
  to match all other dialogs; add minsize(500, 340)
- PresetCatalogDialog: add minsize(600, 400) to prevent collapse on resize

tone_manager.py
- Wrap json.load() in try/except JSONDecodeError; raises ValueError with
  a readable message instead of a raw parse traceback

docs/HLX_GENERATION.md
- Add "Three named snapshots" to What the AI Generates table
- Fix "What It Does NOT Generate" snapshot row — snapshots ARE generated
  with distinct per-block bypass states; only parameter value overrides
  require HX Edit
- Update model catalog table: ~50/12/8/8/6/6/5 → 71/19/11/10/8/9/7/4/3

docs/LLM_PROVIDERS.md
- Update intro to describe both ✨ Label Tone and 📦 Generate Preset;
  clarify that a single provider config is shared by both features

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- _sanitize_params(): validates and clamps all LLM-provided block params
  against model.default_params schema; strips unknown keys; collects warnings
- build_hlx(): now returns (dict, list[str]) with param warnings; clamps
  position to [0, MAX_BLOCKS-1]; uses sanitized params instead of raw LLM values
- _strip_fences(): adds prose fallback extraction via outermost {...} search,
  handling responses like "Here is the JSON: {...} Let me know if anything is wrong."
- generate_hlx_preset(): tracks skipped unknown model IDs and truncated blocks;
  unpacks build_hlx tuple; appends all warnings to PresetResult; on retry
  (attempt > 0) prefixes user message with contextual error hint
- PresetResult: new warnings: list[str] field (default_factory=list)
- _build_system_prompt(): constraint-first ordering (critical rules before 7800-char
  catalog); adds 2-block worked example to anchor weaker model JSON structure
- _build_result_panel(): "Signal Chain (N blocks)" header; amber ⚠ warnings
  strip shown when result.warnings is non-empty

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
Introduces real-world gear name aliases to bridge the gap between user
descriptions and Line 6 code names (e.g. "Tube Screamer" → Scream 808,
"Marshall JCM800" → Brit J45 Nrm). Works at two layers:

- HXModel.aliases field populated for 32 models across Amp, Distortion,
  Delay, Modulation, and Dynamics categories
- catalog_for_prompt() now includes aliases inline so the LLM sees them
  in the catalog it already receives
- _match_gear_hints() pre-matches user description against all aliases
  (case-insensitive substring) and returns explicit model_id hints
- generate_hlx_preset() injects hints into the user message before every
  API call so even weak models get direct model_id guidance

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
When a weak LLM invents plausible-looking model IDs (e.g. HD2_AmpFenderDeluxeNrm,
HD2_ReverbPlateClassic) instead of using the catalog, the pipeline now attempts
to recover rather than discard the block:

1. Category is inferred from the ID prefix (HD2_Amp* → Amp, HD2_Delay* → Delay)
2. The name fragment is camel-case tokenized after stripping the prefix
3. Tokens are scored against catalog display names (+2) and aliases (+3)
4. Highest scorer with score >= 2 is substituted; otherwise the block is skipped

Validated against the full Tom Petty test (6 hallucinated IDs): 5/6 recover
correctly — including the amp — producing a valid working preset. HD2_EQStudio
correctly scores 0 and is dropped.

Recovery warnings surface through the existing amber warnings strip in the UI.
System prompt rule 1 updated to instruct the model to pick the closest available
option rather than inventing a name.

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
## Distortions → ## Distortion
## Dynamicss → ## Dynamics  (was double-s)
## Modulations → ## Modulation
## Delays → ## Delay
## Reverbs → ## Reverb

Used an explicit heading map instead of naive f"{cat}s".

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
Rendered export of the current _build_system_prompt() output including
the full 71-model catalog with aliases.

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
…provements

Based on analysis of two-model test responses (ChatGPT o4-mini and qwen2.5-coder):

- _CHAIN_RANK dict: expected category order for signal chain validation
- Signal chain order check in generate_hlx_preset(): warns (no reorder) when
  blocks are out of category order (e.g. Distortion after Amp)
- _fuzzy_param_key(): 3-pass name rescue — exact, substring, camelCase token
  overlap (catches ChannelVolume→ChVol, Vol→ChVol)
- _sanitize_params(): rescue pass before strip; substitution warnings surfaced
  to user via existing warnings strip
- System prompt rule 4: clarify position 0 = first in chain
- System prompt rule 7: common param name abbreviations (ChVol, Drive, etc.)

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
…t conventions, aliases

- Enable Trails=True on all Delay/Reverb blocks (both @trails in HLX output and
  model default_params) — essential for seamless snapshot switching per Signal
  Theory, Tone Junkie, and Helix community consensus
- System prompt rule 6: add sane starting ranges (Drive 0.3–0.7, Reverb Mix
  0.10–0.35, Delay Feedback 0.30–0.55, ChVol guidance)
- System prompt SNAPSHOTS section: genre-specific naming patterns (Rock, Worship,
  Blues/roots) replacing generic example
- New aliases: Two-Rock→Litigator, Bogner Ecstasy→Divided Duo, Carol-Ann→
  Interstate Zed, Princeton Reverb→Voltage Queen, El Capistan→Transistor Tape,
  BigSky shimmer→Ganymede, Carbon Copy→Simple Delay, pad/mod/infinite reverb variants

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- ConnectDialog: add hardware setup hint (USB cable, MIDI channel matching,
  refresh tip); persist last port+channel to ~/.hxstomp/config.json and
  auto-restore on next open
- Empty state: expand MIDI connect step to include MIDI channel guidance
- Help menu (new): Getting Started modal with two-section quick-start guide
  (MIDI connection + HLX import steps); doc links to MIDI_REFERENCE.md,
  LLM_PROVIDERS.md, HLX_GENERATION.md via OS viewer (_open_doc helper)
- GeneratePresetDialog: expand hint to include 3-step HX Edit import
  instructions and link to line6.com/software
- Live Controls looper: replace abbreviated labels (OD/Rev/½Spd/Once) with
  full names (Overdub/Reverse/Half Spd/Play Once)

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
Catalog (hx_models.py — 71 → 80 models):
- Amps: Mandarin 80 (Orange), Essex A15 (Vox AC15), Placater Clean
  (Friedman BE-100 Nrm), Line 6 Badonk, Grammatico NYC, Hiway 100 (Hiwatt)
- Dynamics: LA Studio Comp (LA-2A optical compressor)
- Modulation: Harmonic Tremolo, Pattern Tremolo

UI quick wins (soundboard_ui.py):
- Tone card subtitle: "PC X · SY" → "Preset X  ·  Snap Y"
- Status bar: "Bank X  PC Y  SZ" → "Setlist X  Preset Y  Snap Z"
  (Setlist label for bank_lsb 0–3, Bank label otherwise)
- ToneDialog: hint row explaining Bank LSB 0–3 = Setlist 1–4
- Live Controls panel visibility now persists across sessions
  via live_panel_visible key in config.json

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
Catalog (80 → 84 models):
- Amp: Fullerton Nrm (Fender Princeton-style, VERIFY US prefix)
- Distortion: Stunner 808, Deez One Vintage, Splitband (all VERIFY)
- Moved Princeton aliases from Voltage Queen → Fullerton Nrm

Hallucination audit:
- Renamed HD2_AmpPlacaterNrm display name "Placater Clean" → "Placater Nrm"
  to match Line 6 Nrm/Dirty suffix convention
- Added # VERIFY comments to 7 uncertain model_id lines:
  Mandarin 80, Essex A15, Grammatico NYC, Pillars OD, plus the 3 new Tier B
  distortion entries
- Expanded file docstring to explain the VERIFY convention

Doc sync:
- README.md: model count 71 → 84 (project structure + roadmap)
- docs/HLX_GENERATION.md: updated count table (all 8 categories)
- system_prompt.md: regenerated from live catalog_for_prompt() output

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- Add HLXWorkspacePanel(CTkFrame) and PresetCatalogPanel(CTkFrame) as
  embeddable panel classes extracted from the former dialog classes
- Simplify GeneratePresetDialog and PresetCatalogDialog to thin wrappers
  that embed the new panel classes (backward-compatible)
- Fix _BG_TOOLBAR NameError in llm_generator.py (was defined only in
  soundboard_ui.py but referenced in PresetCatalogDialog)
- Restructure SoundboardApp with CTkTabview: 🎸 HLX Generator (default)
  and 🎵 Soundboard tabs
- Move toolbar, live panel, grid, and status bar into Soundboard tab
- Remove Preset/Catalog toolbar buttons (now always visible in HLX tab)
- Update Tones menu: replace dialog launchers with tab-switch shortcut
- Update window title and minimum size (700×520)

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- README: update Quick Start (tab layout description, HLX tab as default)
  update AI Preset Generation step 1 (no toolbar button — just open tab),
  update Preset Catalog section (embedded panel, not a toolbar dialog),
  remove duplicate anthropic install step (already in requirements.txt)
- docs/HLX_GENERATION.md: rewrite Step 1 to reflect tab-based navigation
- docs/LLM_PROVIDERS.md: split Option C in-app path for each provider
  (HLX Generator tab vs ✨ Label Tone toolbar button); update Ollama section
  and Switching Providers section to reference the HLX tab
- requirements.txt: fix misleading comment on anthropic (it's the default
  dep, not a special optional install); fix openai/gemini comments to show
  the actual pip install command rather than "uncomment"
- llm_generator.py ProviderConfigDialog: add per-provider key-source hint
  beneath the API Key / Base URL field so first-time users know where to
  get credentials without leaving the app

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- soundboard_ui: add _BG_BASE/SURFACE/CARD/INPUT design tokens + aliases;
  tone cards show visible inactive border (#2a2a2a), hover highlights
  wrapper border, category badge dot (8×8 top-right) from _TONE_CAT_COLORS;
  status bar replaces dot+label with a CTkFrame connection pill;
  scroll grid uses _BG_BASE instead of hard-coded value
- llm_generator: add _PROVIDER_COLORS dict + _BG_CARD/INPUT/SURFACE;
  provider row gets a live-colored ● dot (brand color when key set,
  amber when missing); signal chain blocks taller with separate emoji /
  name / category rows and ▸ arrow; catalog row cards get border_width=1
  + colored left accent strip from first block's category;
  ProviderConfigDialog header shows 14×14 colored provider badge

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
Critical:
- HLXWorkspacePanel._worker: catch all exceptions (not just LLMGenerationError)
  so thread failures surface as error messages instead of silently dying
- HLXWorkspacePanel._save_hlx: wrap catalog.save_preset in try/except;
  show messagebox + red status label on disk write failure

Validation:
- ProviderConfigDialog._save: prompt user to confirm before saving an empty
  API key for cloud providers (Anthropic, OpenAI, Gemini)
- tone_manager.load: wrap Tone.from_dict list comprehension; re-raise
  KeyError/TypeError as ValueError with file path and missing field context

Design token cleanup:
- Add _BORDER_DIM, _BG_TEXT_INPUT, _TEXT_WARN, _BG_WARN, _COL_DISC tokens
  to both llm_generator.py and soundboard_ui.py
- Replace all remaining hard-coded #333333, #2b2b2b, #e8a838, #e74c3c,
  #2a2000, #1e1e1e, #252525 usages with their token equivalents
- Fix two residual #1c1c1c usages in soundboard_ui (pane scroll bg → _BG_BASE,
  _activate_tone card border refresh → #2a2a2a matching _render_card)
- Fix catalog mini-chain separator: → → ▸ to match main signal chain style

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
Covers all pure-Python and I/O logic in hlx_builder.py, hx_models.py,
llm_generator.py, and tone_manager.py — no API key or network required.

Groups:
- TestStripFences (5) — LLM response markdown/prose extraction
- TestFuzzyRecoverModelId (5) — hallucinated model ID recovery
- TestMatchGearHints (4) — real-world gear alias matching
- TestSanitizeParams (5) — parameter clamping + fuzzy key rescue
- TestBuildHlx (8) — .hlx JSON construction, auto-cab, name truncation
- TestCatalogSanitize (4) — preset name → safe filename
- TestCatalogForPrompt (5) — LLM system prompt catalog content + filtering
- TestGetProvider (6) — provider instantiation from config, fallback, key pass-through
- TestToneValidate (7) — MIDI range validation boundaries
- TestAllModelsIntegrity (6) — data integrity: no empty IDs, paired cabs exist
- TestGenerateHlxPresetStub (8) — full pipeline with StubProvider (no network)
- TestGenerateHlxPresetErrors (2) — no-amp and invalid-JSON error paths
- TestSaveHlx (3) — file write, valid JSON, schema key
- TestPresetCatalog (4) — save, list newest-first, remove entry (tempdir)

tkinter/customtkinter are stubbed at the top of the file so the suite
runs in headless environments (CI, servers without a display).

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
…ilities

- test_tone_manager.py (31 tests): ToneManager CRUD, persistence/round-trip,
  load error handling, Tone.to_dict/from_dict, validate boundary conditions
- test_midi_and_utils.py (62 tests): CC constant values, HXStompMidi validation
  and tuner state machine (mido stubbed), MockHXStompMidi API parity and
  behavior, _contrast_color/_adjust_brightness/_muted_color color utilities,
  load_config/save_config I/O with _CONFIG_PATH patching
- Also fixes a discovered behavior: _contrast_color does not guard against
  invalid hex characters (only checks string length) — test documents this

Total suite: 165 tests, 0 failures, no network/hardware/display required.

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
soundboard_ui.py: _contrast_color, _adjust_brightness, _muted_color now
catch ValueError on invalid hex digits (length-6 strings like "#xyz123"
previously crashed; now return safe fallbacks #ffffff / input / fg).

main.py: MockHXStompMidi now mirrors all input validation from HXStompMidi:
- press/release_footswitch: raises ValueError for invalid FS numbers (incl. FS6)
- select_snapshot: raises ValueError for values outside 0–9
- set_exp1/2: raises ValueError for values outside 0–127
Imports _FS_CC from midi_interface to share the same FS→CC mapping.

test_midi_and_utils.py: update test_invalid_hex_raises → test_invalid_hex_returns_white
to reflect the corrected safe-fallback behavior.

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
main.py: wrap top-level imports in try/except ImportError — missing mido or
customtkinter now prints a clear install hint and exits cleanly instead of
crashing with a raw traceback.

tone_manager.py: call tone.validate() on every entry during load(), raising
ValueError with the tone name and field if MIDI values are out of range (e.g.
preset=200). Add ToneManager.create_empty(filepath) classmethod for callers
that need a blank manager without triggering a file load.

soundboard_ui.py:
- SoundboardApp.__init__ catches ValueError from ToneManager and shows a
  messagebox, then continues with an empty preset list instead of crashing.
- ToneDialog._ok() now rejects empty tone names and names longer than 64
  characters with a user-facing error before constructing the Tone object.

llm_generator.py: get_provider() prints a visible warning when the configured
provider name is not recognised, rather than silently falling back to Anthropic.

.github/workflows/test.yml: new CI pipeline running the 165-test headless suite
against Python 3.9, 3.11, and 3.12 on every push and pull request.

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
claude and others added 21 commits March 28, 2026 00:35
…ting

llm_generator.py: Anthropic and OpenAI client constructors now pass
timeout=60.0; Gemini generate_content passes request_options={"timeout":60}.
Ollama already had timeout=30 on its urlopen call. All providers now have
an upper bound on API call duration — hung requests surface as a
LLMGenerationError instead of waiting indefinitely.

test_tone_manager.py: five new tests (170 total):
- test_load_invalid_preset_raises: preset=200 in file raises ValueError
  naming the offending tone and field
- test_load_invalid_snapshot_raises: snapshot=8 in file raises similarly
- test_create_empty_has_no_tones: create_empty() starts with []
- test_create_empty_filepath_set: create_empty() stores the path correctly
- test_create_empty_save_works: create_empty() → add → save → reload works

README.md: new Troubleshooting section covering the four most common failure
modes: missing dependencies, no MIDI ports, AI generation errors, and corrupt
presets.json — each with the specific command to diagnose and fix it.

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- hlx_builder: extract build_hlx_prompt() and parse_hlx_response() from
  generate_hlx_preset(); harden _build_system_prompt() footer with explicit
  JSON-only instruction; generate_hlx_preset() refactored to use helpers
- llm_generator: add "📋 Manual Mode" button to HLXWorkspacePanel;
  add ManualHLXDialog two-step wizard (copy prompt → paste response →
  validate/import) with inline error messages and background threading
- test_hlx_builder: 15 new tests for build_hlx_prompt, parse_hlx_response,
  and generate_hlx_preset via helpers (185 total, was 170)
- README: add Manual Mode subsection under AI Preset Tools

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
…ce and main

Function/method return-type annotations like `-> str | None` are evaluated at
definition time in Python 3.9 (PEP 604 union syntax requires 3.10+). Both
midi_interface.py and main.py were missing `from __future__ import annotations`,
causing TypeError when the test suite imported them under Python 3.9.

All other source files (hlx_builder, tone_manager, llm_generator, soundboard_ui,
hx_models) already had this import. Adding it to the two remaining files makes
all annotations lazy strings on 3.9, matching the rest of the codebase.

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
README:
- Rename title to "HX Stomp — HLX Generator & Soundboard"
- Rewrite opening description to lead with AI Preset Tools
- Swap Part 1/Part 2: AI Preset Tools is now Part 1, MIDI Soundboard is Part 2
- Reorder Troubleshooting: AI errors before MIDI detection issues
- Reorder Project Structure to list AI files (llm_generator, hlx_builder,
  hx_models) before MIDI files, and docs in HLX-first order
- Update bridge paragraph cross-references to match new part numbers

soundboard_ui.py:
- Window title: "HX Stomp — HLX Generator & Soundboard" (HLX first)
- Tones menu: move "🎸 Open HLX Generator" above "✨ Generate Tone…"

Tab default (HLX Generator shown on launch) was already correct — no change.

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- Fix 5 wrong model IDs confirmed against community firmware sources:
  HD2_AmpUSFullertonNrm → HD2_AmpFullertonNrm (no US prefix)
  HD2_AmpGrammaticoNYC → HD2_AmpGrammaticoNrm (NYC variant does not exist)
  HD2_AmpDasBenzin → HD2_AmpDasBenzinLead (Lead/Mega channels exist, no bare suffix)
  HD2_AmpPlacaterNrm → HD2_AmpPlacaterClean (Clean/Dirty channels, not Nrm)
  HD2_AmpRevvGen120 → HD2_AmpRevvGenRed (Red/Purple channels, no Gen120)
- Remove all 6 VERIFY comments; IDs confirmed via helix-preset-viewer and phelix sources
- Add 12 new amp models: MandarinRocker, BritJ45Brt, CaliIVLead, RevvGenPurple,
  DasBenzinMega, GermanXtraBlue, GermanXtraRed, GrammaticoBrt, GSG100,
  USSuperNorm, USSuperVib, WhoWatt100 — total amps 26 → 38
- Expand aliases on 15 previously alias-free models (delays, reverbs, modulation,
  dynamics) improving _match_gear_hints() coverage
- 185 tests still pass

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
Fix six failure modes identified from manual commits:

grab_set() timing (TclError on X11/Wayland):
- Extract _safe_grab(window) to module level in llm_generator.py and
  soundboard_ui.py; removes the duplicate instance method in two classes
- Apply deferred after(10, lambda: _safe_grab(self)) + transient/lift to
  all 7 remaining dialog __init__ methods that used direct grab_set():
  GenerateToneDialog, GeneratePresetDialog, PresetCatalogDialog (llm_generator),
  ConnectDialog, ToneDialog, getting-started window (soundboard_ui)

Clipboard reliability (Tk clipboard broken on Linux):
- Extract _copy_prompt's 55-line Wayland→X11→Tk fallback chain to a module-
  level _set_clipboard(widget, text) → (ok, method, err) function in
  llm_generator.py; ManualHLXDialog._copy_prompt() now calls it in 3 lines

block_states crash (LLM returns null in snapshot):
- hlx_builder.py: snap.get("block_states", {}) → or {} at both call sites
  so that an explicit JSON null no longer propagates as None into the dict
  comprehension

185 tests still pass

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
…e, param warnings

- hx_models.py: Add artist/band/song aliases to 10 key amp models (Slash/GNR→Plexi Brt,
  Hendrix→Plexi Nrm, EVH→PV Panama, Metallica→Cali Rectifire, SRV→Tweed Blues,
  Gilmour/Pink Floyd→Hiway, Santana→Cali IV, Periphery→Revv Red, etc.)
- hx_models.py: Lower ChVol defaults 1.0→0.75 on all 38 amps so weak models produce
  sensible output even without explicit ChVol override
- hlx_builder.py: Add TONE DESCRIPTOR GUIDE to system prompt mapping description words
  (warm/bright/heavy/ambient) to concrete parameter ranges; prevents contradictions
  like Bass=0.4 on a "warm" tone
- hlx_builder.py: Expand example from 2-block to 4-block with explicit ChVol=0.75,
  realistic Mix/Decay values, and Rhythm/Lead/Dry snapshot pattern
- hlx_builder.py: Add parse-time warnings for extreme param values (ChVol>0.92,
  Reverb Decay>0.88, Reverb Mix>0.42) displayed in the result panel

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
Documents all 96 models with gear and artist aliases from hx_models.py.
Includes maintenance note to keep in sync with the source of truth.
Not read by the application.

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
Factual corrections:
- Litigator: remove "Two-Rock" (it's a Line 6 original Dumble-esque design);
  add Dumble, John Mayer, Joe Bonamassa
- Voltage Queen: "Victoria 35115" → "Victoria Electro King" (+ Gibson GA-40)
- Interstate Zed: "Dr. Z Z-Wreck" → "Dr. Z Route 66"; remove "Carol-Ann" entirely
- Hiway 100: remove DR103 (it belongs on WhoWatt); add Hiwatt Custom 50
- WhoWatt 100: add Hiwatt DR-103, Pete Townshend, The Who, David Gilmour, Pink Floyd
- Das Benzin: remove VH4 from Lead (Herbert); VH4 now on Mega where it belongs

Missing artist aliases (names were in descriptions but absent from hint-searchable aliases):
- Arbitrator Fuzz: add Hendrix, Jimi Hendrix, psychedelic rock
- UniVibe: add Hendrix, Jimi Hendrix, psychedelic rock
- Gray Flanger: add Eddie Van Halen, Van Halen, EVH, jet flanger
- Script Mod Phase: add Eddie Van Halen, EVH, funk, Nile Rodgers
- Scream 808: add SRV, Stevie Ray Vaughan

Enrichments:
- Mandarin 80/Rocker: add QOTSA, Mastodon, Kyuss, Josh Homme
- Placater Dirty: add Dave Grohl, Nuno Bettencourt
- Das Benzin Lead/Mega: add Meshuggah, Lamb of God, djent
- German Xtra Red: add Joe Satriani, Trivium
- Revv Gen Red: add Misha Mansoor; Revv Gen Purple: add metalcore/deathcore
- Brit Plexi Nrm: add Eric Clapton
- Deranged Mstr (Rangemaster): add Tony Iommi, Black Sabbath, Eric Clapton
- Matchstick Ch1: add Thom Yorke
- Ram's Head Big Muff: add David Gilmour, shoegaze, Sonic Youth, My Bloody Valentine
- Transistor Tape delay: add David Gilmour, Pink Floyd
- Elephant Man delay: add The Edge, U2, dotted eighth
- Ganymede shimmer: add post-rock, ambient, Sigur Ros
- Cave reverb: add doom metal, Sleep, drone

Also regenerate model_aliases.csv to reflect all changes.

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- Brit J45 Nrm: gear aliases were JCM800 numbers (2203/2204) but the model is a
  JTM-45. Replace with JTM-45/JTM45/JMP. Replace Zakk Wylde/NWOBHM artists
  (belong on JCM800 which HX Stomp doesn't model) with correct JTM-45 artists:
  Angus Young, Bon Scott, AC/DC, Eric Clapton, Bluesbreakers
- Soup Pro: description and alias said "Supro 1695T/Thunderbolt" but confirmed
  Supro S6616. Add Jimmy Page, Led Zeppelin (definitive S6616 users)
- GSG-100: confirmed Dumble OD Special-inspired; add John Mayer, Joe Bonamassa,
  Dumble, David Gilmour as artist aliases
- Mail Order Twin: add Jack White and Beck (Silvertone 1484 community associations)
- Regenerate model_aliases.csv to match

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- Add icon_manager.py with CTkImage loader (lru_cache, graceful fallback)
- Add assets/icons/ with 32 Phosphor Icons PNGs (MIT license, 32x32 white-on-transparent)
- Add custom app-icon.png (128x128)
- Add _resolve_ui_font() to both UI files; replace hard-coded Helvetica
- Add CTkTabview segmented button colors, visible scrollbar styling
- Add wm_iconphoto() window/taskbar icon
- Replace tk.Text with ctk.CTkTextbox in GenerateToneDialog and HLXWorkspacePanel
- Update all toolbar, dialog, and action buttons in soundboard_ui.py with icon_btn()
- Update all dialog and action buttons in llm_generator.py with icon_btn()
- Add tkinter.font stub to both test files to keep headless tests green

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- Regenerate app-icon.png as 512x512 with dark navy rounded rect, HX STOMP
  text, three colored footswitch caps (blue/green/red), and MIDI pin dots
- _set_window_icon() now passes 48/128/256/512px variants via wm_iconphoto
  so X11/Wayland compositor can pick the best fit
- Set wm iconname to "hxstomp" for taskbar grouping (matches .desktop WMClass)
- Add _install_desktop() and --install-desktop CLI flag: installs icons to
  ~/.local/share/icons/hicolor/{48,128,256,512}x*/apps/ and writes
  ~/.local/share/applications/hxstomp.desktop with correct Exec path;
  updates gtk icon cache and desktop database when tools are available

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
…ptions

Colors:
- _CAT_COLOR updated to match Line 6 HX hardware color scheme:
  Amp=red, Drive=amber-yellow, Delay=green, Reverb=cyan, Mod=blue-indigo,
  EQ=purple, Dynamics=orange, Cab=dark-gray (replaces arbitrary palette)
- _TONE_CAT_COLORS in soundboard_ui.py aligned to same scheme

Icons:
- Replace _CAT_BADGE emoji dict with _CAT_ICON (Phosphor icon names)
- Download speaker-high, waves, wave-sine, sliders-horizontal, speaker-none
- Signal chain cards and catalog mini-chips now use CTkImage icons with
  text fallback if icon file is missing

Genre tagging:
- Add genre field to PresetResult (default "Other")
- LLM system prompt now requires a genre field (one of 12 labels)
- parse_hlx_response() captures and validates the genre value
- PresetCatalog.save_preset() writes genre to catalog JSON
- Result panel shows colored genre chip next to preset name
- Catalog rows show genre chip next to date

Helpers added to llm_generator.py:
- _model_subcategory(model_id) — derives Fuzz/Chorus/Hall etc. from model_id
- _key_params_summary(blk) — formats 1-2 key params as "Drive 65%  Mix 20%"
- _Tooltip class — 600ms hover tooltip (CTkToplevel, overrideredirect)

Block cards in result panel:
- Icon replaces emoji, subcategory shown as "Delay › Tape Echo", key params
  summary line at bottom, hover tooltip with full name + all params + explanation

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
…pansion)

Adds ~65 new tests across two files:
- test_hlx_builder.py: TestModelSubcategory, TestKeyParamsSummary,
  TestPresetResultGenreField, TestCatDicts — covering _model_subcategory(),
  _key_params_summary(), PresetResult.genre, _CAT_COLOR/_CAT_ICON completeness
- test_icon_manager.py: TestGetIcon, TestIconBtn — covering get_icon() fallback
  paths (empty name, missing file, PIL unavailable), lru_cache hit behaviour,
  all new Phosphor icons, and icon_btn() kwarg forwarding

CI workflow updated to include test_icon_manager in the test command.

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
Updates all display names, window titles, doc titles, and the README to
lead with the AI preset generator as the primary feature. MIDI soundboard
is retained as a secondary capability. System identifiers (hxstomp,
~/.hxstomp/) are unchanged for backward compatibility.

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 68dad1caa8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/test.yml Outdated
Comment on lines +23 to +25
- name: Run test suite (headless — no hardware or display required)
run: |
python -m unittest test_hlx_builder test_tone_manager test_midi_and_utils test_icon_manager -v

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Install dependencies before running test workflow

The test job runs python -m unittest ... immediately after setup-python without installing project/test dependencies, so CI behavior depends on whatever packages happen to be preinstalled on the runner. In clean environments this causes the icon tests to fail because Pillow is missing, which makes the workflow unreliable and can block merges even when code is correct. Add an explicit dependency installation step before invoking the test command.

Useful? React with 👍 / 👎.

Comment thread llm_generator.py
Comment on lines +335 to +337
api_key = cfg.get(f"{name}_api_key", ""),
model = cfg.get(f"{name}_model", ""),
base_url = cfg.get(f"{name}_base_url", ""),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Read fallback provider settings from resolved provider name

When cfg["provider"] is unknown, get_provider() correctly falls back to AnthropicProvider, but it still reads api_key, model, and base_url from keys derived from the unknown provider name. That means valid anthropic_* settings are ignored in the fallback path, so users can see a fallback message and still fail generation due to an empty key/default model. This should read config using the resolved provider identity.

Useful? React with 👍 / 👎.

edonahue and others added 7 commits March 29, 2026 16:43
- test.yml: add explicit 'pip install -r requirements.txt' step so Pillow
  and other deps are available on clean runners (fixes test (3.11) failure)
- llm_generator.py: use resolved cls.name when building config key names so
  the Anthropic fallback path correctly reads anthropic_api_key / anthropic_model
  instead of keys derived from the unknown provider name

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- get_provider(): add `resolved = cls.name` so fallback to Anthropic
  reads anthropic_api_key/model from config, not unknown-provider keys
- HLXWorkspacePanel: remove two superseded _on_result definitions that
  were silently shadowed by the final auto-save variant

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
- get_provider(): add resolved = cls.name so fallback to Anthropic
  reads anthropic_api_key/model from config, not unknown-provider keys
- HLXWorkspacePanel: remove two superseded _on_result definitions that
  were silently shadowed by the final auto-save variant

https://claude.ai/code/session_01X9hWeCdBCmCV8XDdNpCRvn
…fix ALSA CI step

Root causes of CI failure:
- llm_generator.py was overwritten to a single garbage line in commits e76bc45/03478e9
  ("Fix provider fallback key lookup"). Restored to the correct 2112-line version
  from commit 6aad34f which already included the provider fallback fix.
- Pillow (PIL) was not listed in requirements.txt but is required by icon_manager.py
  for CTkImage construction; test_icon_manager was returning None for all get_icon()
  calls in CI because PIL was absent.
- CI workflow lacked the `apt-get install libasound2-dev libjack-dev` step required
  by python-rtmidi to compile; added before pip install so the dep resolves cleanly.

Also fixed test_icon_manager.py: stub class renamed from _CTkImageStub → CTkImage
so that result.__class__.__name__ == "CTkImage" assertion passes in headless mode.

All 250 tests now pass locally:
  python -m unittest test_hlx_builder test_tone_manager test_midi_and_utils test_icon_manager

https://claude.ai/code/session_01KqxYUVRUynBF9vhd2DGvvY
- Add _resource.py: PyInstaller-safe resource_path() helper using sys._MEIPASS
- Add __version__.py: single-source VERSION = "1.0.0"
- Update icon_manager.py to use resource_path() for bundled icon dir
- Update main.py: use resource_path() for --install-desktop icon, import VERSION
- Update soundboard_ui.py: show VERSION in window title
- Add openai>=1.0.0 and google-generativeai>=0.8.0 to requirements.txt
- Add hlx_generator.spec: PyInstaller onedir spec (all 3 LLM providers bundled)
- Add build_release.py: platform dispatcher → .deb / .dmg / .exe
- Add packaging/deb/DEBIAN/control + postinst for dpkg-deb packaging
- Add packaging/nsis/installer.nsi.template for Windows NSIS installer
- Add scripts/make_icons.py: PNG → .icns (macOS) + .ico (Windows) converter
- Add .github/workflows/release.yml: 4-runner matrix (ubuntu-22.04, macos-13,
  macos-14, windows-latest) triggered by vX.Y.Z tag; publishes GitHub Release
  with per-platform download table and unsigned-app workaround docs

https://claude.ai/code/session_01KqxYUVRUynBF9vhd2DGvvY
New test files:
- test_resource.py (8 tests): resource_path() in non-frozen and frozen
  (sys._MEIPASS) modes, return type, subdirectory preservation, real asset exists
- test_build_release.py (17 tests): _version() reading, arch auto-detection
  (x86_64→amd64, arm64/aarch64→arm64), build_linux/build_macos/build_windows
  error paths, DEBIAN/control template substitution, NSI template substitution,
  dpkg-deb and hdiutil invocation verification

Extended test_midi_and_utils.py:
- Group L — TestLooperControls (15 tests): every looper method verified against
  exact HX Stomp CC number and value (CC60-67, CC64 tap tempo, CC59 EXP toe)
- Group M — TestGetProvider (10 tests): get_provider() factory for all 4
  providers (Anthropic/OpenAI/Gemini/Ollama), unknown fallback to Anthropic,
  api_key/model pass-through, default_model used when not in config

Fix .github/workflows/release.yml:
- GITHUB_OUTPUT bug: replace Python print() with echo >> $GITHUB_OUTPUT so
  steps.version.outputs.version is correctly populated in the publish job
- Add SHA256 checksum generation (sha256sum * > SHA256SUMS.txt) uploaded to Release
- Add Linux binary smoke test after PyInstaller build (--list-ports || true)

Update .github/workflows/test.yml:
- Run new test modules (test_resource, test_build_release) in CI
- Add hlx_generator.spec syntax validation (ast.parse)
- Add build_release.py --help smoke test

All 299 tests pass locally (python -m unittest ... -v).

https://claude.ai/code/session_01KqxYUVRUynBF9vhd2DGvvY
README.md: full rewrite — 17.4 KB → ~4 KB
- Pain-point-first opening (why this exists)
- Centered logo + tagline + 4 badges (CI, Python, License, Release)
- Two-column feature table (MIDI Soundboard | AI Preset Builder)
- Two-track install section: Download (platform installer table +
  collapsible unsigned-app workaround) and Run from source
- 4-step FTUX Quick Start with keyboard shortcut hint
- Screenshot comment placeholders for user to fill locally
- Concise CLI flag table (5 most useful flags)
- Links to docs/ for deep dives (HLX_GENERATION, LLM_PROVIDERS, MIDI_REFERENCE)
- Removed: full project structure tree, roadmap, full MIDI CC table,
  full presets.json schema, verbose troubleshooting, full AI provider setup

CHANGELOG.md: new file — v1.0.0 entry covering all features, providers,
example presets, keyboard shortcuts, and cross-platform installers.
Follows Keep a Changelog format.

docs/screenshots/README.md: new guide for the user on what screenshots
to capture (soundboard.png hero + ai-builder.png), recommended state/size,
and exactly how to swap in the <img> tags in README.md.

https://claude.ai/code/session_01KqxYUVRUynBF9vhd2DGvvY
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants