# Package and release audio plug-ins

> Choose platform runners, validate VST3, Audio Unit and CLAP builds, prepare installers and downloads, and understand hardware delivery limits.

Canonical: https://maruaudio.com/docs/packaging-and-releasing-plugins
Documentation index: https://maruaudio.com/llms.txt

A musician needs a plug-in that installs, opens in their DAW, restores their
session and survives an update. Reaching that point takes more than compiling
the DSP: build the complete native bundle, validate it on its target platform,
package its interface and resources, and test the delivered archive or installer.

Use the same Maru CLI locally and in CI. Pin the toolchain version in your
project, install the components for your selected targets, and keep the build,
validation and packaging reports alongside the resulting downloads.

## Build on the platform you intend to support

VST3 and CLAP are cross-platform APIs. Their compiled binaries are specific to
an operating system and architecture. Steinberg documents Windows VST3 binaries
as DLLs and macOS VST3 binaries as Mach-O bundles. Sharing a TypeScript project
does not make the resulting native file interchangeable between them.
<a href="https://github.com/steinbergmedia/vst3sdk#system-requirements" target="_blank" rel="noopener noreferrer">Steinberg's SDK requirements</a>
list the platform compiler families.

Our recommendation is native CI runners:

| Intended output | Build and validate on | Important boundary |
| --- | --- | --- |
| macOS VST3, AU, CLAP and standalone | macOS, with the selected Apple SDK and architecture | ARM64 and Intel are separate outputs unless a universal binary is deliberately produced and verified. |
| Windows VST3 and CLAP | Windows with the supported Windows SDK and compiler | Test the editor, resources and installed bundles in the Windows hosts you support. |
| Linux VST3 and CLAP | The supported Linux distribution/toolchain | Qualify the native host, UI adapter and runtime dependencies; a Linux build is not established by macOS results. |
| AAX | A supported runner with the authorized Avid SDK and signing workflow | Distribution requires Avid signing and validation in Pro Tools. |
| Hardware | A runner with the exact target compiler, followed by tests on the board | A desktop plug-in binary is not firmware. |

Trigger the complete CI matrix from either macOS or Windows. Each runner builds
and tests its own platform's outputs. Cross-compilation still requires matching
SDKs, dependencies and target-host tests, so use native runners for releases.
Audio Unit and Apple's signing/notarization tools use the macOS runner.

## Keep the native bundle intact

On macOS, `.vst3`, `.component`, `.clap` and `.app` outputs are directory bundles.
The compiled executable is under `Contents/MacOS/`; the embedded interface may
contain HTML, CSS and JavaScript under `Contents/Resources/`. Both belong in the
product. Shipping only the UI does not ship the plug-in, and removing it breaks
the editor.

Keep the module's parameters, state, presets and resources with its canonical
source. Define a version and stable identity deliberately before release. Use
that identity for builds and retain it when testing updates and session recall.
Avoid changing public parameter meaning without a planned state migration for
already-released sessions.

From your project directory, build and verify the selected formats:

```sh
maru --version
maru doctor
maru module doctor
maru plugin build src/index.ts --release --format vst3 --out build/vst3
maru plugin build src/index.ts --release --format au --out build/au
maru plugin build src/index.ts --release --format clap --out build/clap
maru plugin build src/index.ts --release --format standalone --out build/standalone
maru module verify src/index.ts --build-root build
```

`--release` selects the release identity and build instrumentation. Apply
Developer ID signing, notarization and installer validation in the packaging
steps below.

`maru plugin build --format all` builds the project's configured native formats
and records unavailable targets. Set `build.nativeFormats` in `.maru/config.json`
to choose them. The default set is VST3, CLAP, AU and standalone; add AAX when
your project supplies its SDK and delivery requirements. This command does not also generate every installer,
SDK package or hardware image. Explicitly choose the output set your project
promises and fail its release when any required output is missing.

## Validate what the customer will receive

Inspect the generated `build-report.json` and the combined module verification
report. Compilation, format validation, signing and installation are separate
results. An unavailable or skipped check is not passing evidence for that feature.

Run the format-owned checks, then exercise audio/MIDI, sample-rate and block-size
changes, both parameter endpoints, presets, save/reopen, bypass and two independent
instances. VST3 uses Steinberg's validator. CLAP has an upstream
<a href="https://github.com/free-audio/clap-validator#usage" target="_blank" rel="noopener noreferrer">CLAP validator</a>. AU uses
Apple's `auval` and an AudioComponent host. Format checks supplement actual DAW
tests; they do not prove every host or editor behaves correctly.

For a first manual session, follow [Testing your VST](https://maruaudio.com/docs/testing-your-vst.md).
Retest the extracted archive or installed payload, including its editor and
resources. Keep the output hashes, tool versions and reports for that exact file.

## Package downloads and installers

Give customers a small, clearly named download. A module project puts its final
outputs directly in `build/` by default:

```text
build/
  README.md
  macos-arm64/
    plugins/                 complete native bundles
    standalone/              application bundle
    installers/              actual installer, when built
    archives/                per-format ZIPs
    install/                 guide, manifest and matching uninstaller
  web/
    app/                     standalone website with playback host
    module/                  reusable browser module for another host
  documentation/             manual, image and release notes
  SHA256SUMS
```

Set `build.output.directory` in `.maru/config.json` to choose another output
root. Enable `build.output.productDirectory`, `build.output.versionDirectory`,
or both to group handoffs, for example `build/meteora/1.0.0/`. Both are off by
default; the module folder, bundle metadata and descriptive archive names
already identify the product and version. Paths are relative to the project
root. Internal compiler and staging files stay under `.maru/cache/`.

Rebuilds safely replace the selected outputs after validation. They do not
clean the whole directory first. With version grouping, a new version gets a
new folder; source edits at the same unpublished version update its existing
folder. Keep published releases immutable in your release storage. A failed
attempt preserves the last successful output, and the README identifies the
failed attempt separately. Remove old outputs through an explicit cleanup step.

Only list platform/architecture folders that were actually built. Keep compiler
output, local caches, credentials and debug logs outside customer downloads.
Version archive filenames and include the format, OS and architecture. Preserve
bundle metadata, executable modes and links when archiving; use a platform-aware
archiver, then extract and compare the resulting payload.

Installers should let musicians select the formats their DAW needs. Derive
installer destinations, manual-install instructions and uninstall paths from
one install plan. Include the matching uninstaller and test upgrades and removal
without deleting presets or unrelated products. An installer XML/script is a
plan; call it an installer only after creating and inspecting its `.pkg` or
Windows installer executable. Build an unsigned local candidate when supported,
then test the signed distribution package separately.

For macOS downloads outside the App Store, use the appropriate Developer ID
signatures, notarize the distribution container and staple where supported.
Verify the final signatures and acceptance, including plug-ins loaded inside a
DAW. An ad-hoc signature can provide a consistent local seal without providing
Developer ID trust or notarization. See Apple's
<a href="https://developer.apple.com/developer-id/" target="_blank" rel="noopener noreferrer">Developer ID guidance</a> and
<a href="https://developer.apple.com/documentation/security/notarizing-macos-software-before-distribution" target="_blank" rel="noopener noreferrer">notarization workflow</a>.
Use the Windows signing process for Windows delivery; an Apple signature does
not sign a Windows binary.

Include the product license, third-party notices, minimum requirements, exact
formats/architectures, install/uninstall steps, version, support contact and
release notes. Check your distributor's current submission requirements before
uploading; a ZIP that works locally is not evidence of marketplace acceptance.

## Run GitHub Actions as a native matrix

Use one job per supported OS/architecture, with `strategy.fail-fast: false` so
one failed row does not cancel the other evidence. GitHub's
<a href="https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/run-job-variations" target="_blank" rel="noopener noreferrer">matrix documentation</a>
explains runner selection and failure handling. Use explicit runner images and
record the actual architecture; do not infer it from a moving `latest` label.

Each job needs the pinned project dependency lockfile, Node.js, the exact Maru
CLI and component versions, its native compiler/SDK, the required build tools,
and compatible validators. Browser qualification also needs its supported
Chromium runtime. A headless validator does not replace interactive editor,
audio-device, clean-install or hardware tests.

Provision these tools explicitly for the selected lane:

- **macOS:** Xcode/Command Line Tools and the selected macOS SDK, CMake, Maru's
  pinned native compiler components, the VST3 SDK/validator, CLAP SDK/validator,
  and Chromium for browser qualification. `auval`, `codesign`, `pkgbuild` and
  `productbuild` supply the Apple format and packaging tools; distribution also
  uses `notarytool` and the appropriate signing credentials.
- **Windows:** the supported MSVC/Windows SDK environment, CMake, the pinned
  native compiler components, Chromium and Windows builds of the applicable
  validators.
- **Linux:** the chosen C/C++ compiler, CMake, pinned native components,
  Chromium, applicable validators and the declared UI/runtime dependencies.
  Record the distribution and ABI used for the actual host checks.
- **Hardware:** the exact board SDK/cross-compiler, adapter and emulator or
  device runner selected by its profile. A CPU architecture match is insufficient.

The public CLI supplies headless build and validation commands, runtime
harnesses, fixture loaders and structured reports. Install and verify pinned
compiler, browser and validator components explicitly. System and proprietary
SDKs and signing credentials are runner inputs.

Run the pipeline in this order:

1. Install locked project dependencies and check CLI/component readiness.
2. Resolve the requested targets and report missing SDKs/runners early.
3. Build and qualify the exact module on each supported runner.
4. Package and verify archives and installers on that same platform.
5. Retain reports even on failure; expose successful local candidates separately.
6. In an explicit release job, apply signing/notarization and publish only the
   complete required output set.

Call the same public commands in CI as in local builds. Keep platform
provisioning and signing in explicit job steps so the workflow is reproducible
on a clean runner.

Run untrusted pull-request checks without release credentials. Use a separate
release job with narrowly scoped permissions and protected signing credentials.
Cache compilers/components by exact CLI, component, OS, architecture and relevant
input identity. Cached build bytes are not fresh validation results.

## Retrieve and test the outputs

Upload already-created ZIPs, installers, checksums and reports as Actions
artifacts. Avoid uploading a raw macOS bundle as loose files: GitHub's artifact
action documents that executable permissions can be lost. A prebuilt archive
preserves its internal bundle layout. See the
<a href="https://github.com/actions/upload-artifact#permission-loss" target="_blank" rel="noopener noreferrer">artifact action's permission guidance</a>.

For example, after your project's build/package steps have succeeded, a GitHub.com
workflow can use a step like this. Adjust the paths to the project's real layout
and pin the reviewed action commit in a release workflow:

```yaml
- name: Retain native download candidates
  uses: actions/upload-artifact@v7
  with:
    name: plugins-${{ runner.os }}-${{ runner.arch }}-${{ github.sha }}
    path: |
      build/**/archives/*.zip
      build/**/installers/*
      build/**/SHA256SUMS
    if-no-files-found: error
```

Add a separate report upload using `if: always()` with the actual report paths;
it must not turn a failed build into a successful release. The upload step alone
does not verify that every requested installer or format exists; the preceding
build/qualification/package gates must enforce completeness.

Download a candidate from the workflow run's **Artifacts** section, verify its
checksum, extract it with a suitable archiver and test that exact payload on its
intended OS/architecture. Keep failed-run reports for diagnosis. Actions artifacts
have retention limits; stable customer downloads should use an explicit GitHub
Release or your delivery service, with versioned files and permanent release notes.

## Hardware is a separate delivery target

A hardware project references the same module through a board profile and host
adapter. It needs that board's compiler, runtime, resources, control mapping,
flash image/package and recovery procedure. Build and emulator results should
be kept separately from physical-device qualification.

Choose a board profile from
[Hardware platforms and profiles](https://maruaudio.com/docs/hardware-platforms.md), then follow
[From module to hardware](https://maruaudio.com/docs/from-module-to-hardware.md)
for the project workflow. Use CI to build and emulate the selected target;
measured latency, xruns, memory fit, codec/MIDI/control behavior and recovery need
the actual device. Flashing or installation is an explicit step. Provide the
exact device/profile/version, checksums and recovery instructions when handing
an image to a tester; do not offer a desktop VST3 or a generic ARM archive as firmware.

Continue with [Publishing](https://maruaudio.com/docs/publishing.md) for the product release
journey and [Native plugins](https://maruaudio.com/docs/native-plugins.md) for command discovery.
