Audio Unit (AU v2 and AU v3)
Audio Unit is Apple's native plugin format on macOS. It's the only
format Logic Pro and GarageBand accept, so shipping into the Apple
pro-audio market means shipping AU. Truce supports both AU v2 (the
legacy .component bundle loaded in-process) and AU v3 (the
sandboxed .appex App Extension loaded out-of-process).
#Status
Opt-in. macOS-only (iOS is planned). Tested in Logic Pro, GarageBand, Ableton Live, and Reaper.
Both AU v2 and AU v3 ship from the same au feature flag and
the same Rust staticlib. What differs is only the bundle layout
and the host integration path.
#Enable
[features]
au = ["dep:truce-au"]
# or, to enable by default:
default = ["clap", "vst3", "au"]
cargo truce install --au2 # AU v2 only — .component bundle
cargo truce install --au3 # AU v3 only — .appex inside a container .app
cargo truce install --au2 --au3
#Requirements
| Format | Toolchain | Signing |
|---|---|---|
| AU v2 | Xcode CLI tools (xcode-select --install) |
$TRUCE_SIGNING_IDENTITY (ad-hoc - works locally) |
| AU v3 | full Xcode (xcodebuild required) |
Developer ID Application — ad-hoc signing is rejected |
AU v3 requires full Xcode because cargo truce install --au3
generates an Xcode project and drives xcodebuild to build the
Swift AudioUnitFactory appex into a container app. The CLI tools
alone don't include xcodebuild.
#AU v3 signing
The AU v3 appex must be signed with a Developer ID (or development)
identity that Apple's pluginkit will accept. Ad-hoc signing (-)
is rejected at registration. Set:
# .cargo/config.toml (gitignored)
[env]
TRUCE_SIGNING_IDENTITY = "Developer ID Application: Your Name (TEAMID)"
Or export it:
export TRUCE_SIGNING_IDENTITY="Developer ID Application: Your Name (TEAMID)"
If TRUCE_SIGNING_IDENTITY is - or unset when you try to install
AU v3, the install bails with a clear error. AU v2 falls back to
ad-hoc and works with -.
#Install paths
| Format | User (default for AU v2) | System (--system) |
|---|---|---|
| AU v2 | ~/Library/Audio/Plug-Ins/Components/{Name}.component/ |
/Library/Audio/Plug-Ins/Components/{Name}.component/ (sudo) |
| AU v3 | system† | /Applications/{Name}.app/Contents/PlugIns/AUExt.appex/ (sudo) |
† = --user falls back to system silently. pkd registration
of ~/Applications/... is unreliable on macOS ≤ 13, so AU v3 is
treated as system-only. cargo truce install --user --au3 lands
at /Applications/... with a one-line note.
The AU v3 appex is embedded inside a container .app at
/Applications/. Apple requires this — App Extensions cannot ship
on their own. The container app is a minimal stub that exists only
to host the appex; you don't interact with it.
After an AU v3 install, pkd (the PluginKit daemon) picks up the
new extension. If a host doesn't see it, run cargo truce reset-au
to flush pkd caches and restart the daemon for a clean re-scan.
#Identifiers
From truce.toml:
[vendor]
au_manufacturer = "MyCo" # 4-char manufacturer code
[[plugin]]
fourcc = "MyFx" # AU v2 subtype (and fallback for v3)
au3_subtype = "MyF3" # optional — distinct subtype for v3
au_tag = "Effects" # "Effects" | "Synthesizers" | "Music Effects"
AU v3 can use a different subtype from AU v2 (au3_subtype).
This matters if you want both versions installed at once without
hosts colliding on the component ID — Logic is particularly strict
about this.
#Build / install / package
cargo truce install --au2 # installs .component only
cargo truce install --au3 # installs .app into /Applications
cargo truce install # all enabled formats (AU v2 + v3 if both in default)
cargo truce build --au2 # bundle into target/bundles/ without installing
cargo truce build --au3 # AU v3 .app into target/bundles/ (signed, ready to copy)
cargo truce package --formats clap,vst3,au2,au3 # installer with AU included
Both --au2 and --au3 produce complete, signed bundles in
target/bundles/. install is a pure copy + pluginkit register
step — the xcodebuild / framework-assembly / inside-out codesign
work all happens at build time, no sudo or /Applications/ write
needed to produce a bundle.
#Validate
cargo truce validate runs auval:
auval -v aufx MyFx MyCo
(Type code from category; subtype and manufacturer from
truce.toml.) AU v3 is validated by walking
/Applications/*/Contents/PlugIns/*.appex and running auval
against each.
#Logs
AU v3 runs in a separate appex process. NSLog output from the
extension doesn't land in the DAW's log — it goes to unified
logging. Stream it live with:
cargo truce log-stream-au
Useful when the AU v3 GUI is black, the appex crashes on load, or parameters don't sync.
#Hosts
| Host | AU v2 | AU v3 |
|---|---|---|
| Logic Pro | ✅ | ✅ |
| GarageBand | ✅ | ✅ |
| Ableton Live | ✅ | ✅ |
| Reaper | ✅ | ✅ |
| Pro Tools | — (uses AAX) | — |
#Gotchas
xcodebuildis mandatory for AU v3. Full Xcode, not just CLI tools.xcode-select -pmust point at a realXcode.app; if it points at/Library/Developer/CommandLineTools, v3 installs fail. Runsudo xcode-select -s /Applications/Xcode.app.- AU v3 ad-hoc signing is rejected. The install path refuses
-and prints a clear message. AU v2 is lenient and works ad-hoc. - AU v3 always installs to
/Applications/(system-wide, needs sudo).cargo truce install --user --au3falls back with a one-line note. AU v2 honors--user(default) and writes to~/Library/Audio/Plug-Ins/Components/with no sudo; pass--systemfor the system path. - Host caches are sticky. If a plugin appears broken after
changing IDs or reinstalling,
cargo truce reset-auflushes the AU caches and restartspkd/AudioComponentRegistrar(usecargo truce reset-aaxfor the Pro Tools AAX cache). If that doesn't help, follow up withcargo truce uninstall --au2 --au3 -p <crate>and reinstall. - v2 and v3 collision. If
au3_subtypeequalsfourcc, hosts may only surface one of them. Use distinct subtypes (e.g.MyFxandMyF3) if both must coexist. - AU v3 is macOS-only. iOS AU v3 is planned; the design mirrors
macOS (same Swift
AudioUnitFactory,UIViewControllerinstead ofNSViewController). Not implemented yet — see the iOS plan for scope.