# SerumAlt agent guidance ## Project SerumAlt is a JUCE 7 wavetable synthesiser using C++17. Project metadata is in `CMakeLists.txt`. Production formats are VST3 and Standalone on Linux, VST3/AU/Standalone on macOS, and VST3 on Windows. First-party classes use `namespace serum`; executable entry points and JUCE's `createPluginFilter` are outside that namespace. ## Build and verification Read README.md's Building section before changing scripts, dependencies, or CMake. It is the maintained source for prerequisites, options and artifact paths. - Linux production: `./build_linux.sh`. - macOS production, on a Mac: `./build_macos.sh`. - Windows x64 VST3, cross-compiled on Linux: `./build_windows.sh`. - Native QA build and execution: `./build_harness.sh --run`. - Shell syntax: `for script in build_*.sh; do bash -n "$script"; done`. Production scripts explicitly enable `SERUMALT_BUILD_PLUGIN` and disable `SERUMALT_BUILD_TESTS`. The harness script does the reverse in a separate directory. Building `SerumAltTest` alone does not execute it; `--run` invokes CTest. When changing CMake, verify production has no `SerumAltTest` target and the harness-only build has no `SerumAlt`, VST3, AU, or Standalone target. Keep existing build trees and local changes intact. Use a new `BUILD_DIR` for clean-build verification. Use a fresh Windows `OUTPUT_DIR` for distribution checks, since staging does not remove extra files. Never edit generated CMakeCache.txt files. The checked-in MinGW toolchain is the single source of cross-compiler configuration. ## Current source layout `CMakeLists.txt` owns the explicit `SERUMALT_SOURCES` list and shared target setup. `cmake/Plugin.cmake` owns production formats and MinGW link flags; `cmake/Harness.cmake` owns the console harness and CTest registration. The harness compiles the same processor/editor sources independently of the plugin. Most C++ files still live directly under `Source/`. Existing implementation subdirectories are `EffectUnits/`, `GUI/`, `Presets/`, `Resources/`, and `Tests/`. `FXProcessor`, `PluginEditor`, `Resources`, and `RAVEButton` remain at the source root. `RAVEButton.{h,cpp}` defines `RaveController`. The lowercase `Source/engine`, `modulation`, `params`, `plugin`, and `synth` directories currently hold guidance, not relocated implementations. Consult their AGENT.md files when editing the related root-level sources. Consult the matching AGENT.md when editing an existing implementation subdirectory. `AUDIT_REPORT.md` is a historical audit and proposed refactor, not a pending instruction to move files. Update the explicit source list and includes only when an actual source move is part of the requested task. ## Style and ownership Follow the surrounding file. Existing C++ generally uses four-space indentation, `#pragma once`, PascalCase types, camelCase members without prefixes, `k`-prefixed constants, scoped enums, and `noexcept` on cheap getters and DSP paths. Use `Count` only for enums that need a size or iteration sentinel. Headers include JuceHeader; implementation files normally include their own header first. Prefer value members or `std::unique_ptr` for owned objects and attachments. `addAndMakeVisible` does not transfer ownership or delete children. Raw allocations returned by `createEditor` and `createPluginFilter` transfer ownership to JUCE callers. Guard parameter lookups and invalid state data. Use `jassert` sparingly for programmer errors and return `bool` from bounded inserts to report failure. ## Real-time and concurrency requirements For new or changed audio paths, allocate buffers during preparation and avoid heap allocation, blocking locks and I/O in `processBlock` or per-sample DSP. Account for variable host block sizes without allocating in the callback. Keep GUI updates on the JUCE message thread. Exchange GUI/audio state through a safe snapshot or bounded handoff; a timer or a writer-only mutex does not make concurrent access safe. These are requirements, not claims that the current code already satisfies them. The historical audit records lazy wavetable allocation, per-block buffer resizing, and unsynchronised modulation/LFO edits. When changing those paths, inspect the current implementation and verify the fix separately. The QA smoke test does not prove real-time safety or absence of data races. ## Scope of guidance Module guidance refines this file for its related sources. Preserve the root real-time and ownership requirements if an example conflicts with them.