PluginBridge β Claude Code Context
What This Is
A JUCE-based VST3/AU plugin that:
- Hosts any third-party VST3/AU plugin with full GUI embedded in Ableton's window
- Crash-isolates unsafe plugins by loading them in a separate Helper process (audio-only mode)
- Exposes ALL hosted plugin parameters via a local MCP server (port 16620)
- Audio routes through shared memory (zero added latency)
- Any AI that speaks MCP (Claude Code, Codex CLI, Gemini CLI) can control any plugin
Current Status (v0.6.0 β 2026-05-17)
- β In-process GUI hosting (full GUI for safe plugins)
- β Safety scanning system (Helper-based pre-test, results cached in safety_db.json)
- β Audio-only mode for unsafe plugins (iZotope, etc.)
- β Ableton-style plugin picker (manufacturer TreeView, search, safety badges)
- β MCP server (port 16620, HTTP JSON-RPC 2.0)
- β Live spectrum analyzer (LUFS / FFT bands / stereo width / centroid / true peak)
- β Multi-instance support + channel dropdown (any PluginBridge track addressable by name)
- β Verified working: Pro-Q 4, God Particle, Little MicroShift, LIMITER
- β οΈ Sprint 7 in progress β MCP param ops route through Helper (not in-process) β EQ changes invisible in GUI
Architecture: HYBRID SAFETY-SCAN
ββ Ableton Process βββββββββββββββββββββββββββββββββββββββββββββββ
β β
β PluginBridge.vst3 β
β βββ PluginBridgeProcessor β
β β βββ getInstalledPluginFiles() β scans VST3+AU dirs β
β β βββ getPluginManufacturer() β reads Info.plist, cached β
β β βββ PluginSafetyDB β safe/unsafe/unknown JSON DB β
β β βββ startBackgroundScan() β pre-tests all unknown plugins β
β β βββ loadPlugin() β orchestrates load flow β
β β βββ McpServer β HTTP MCP port 16620 β
β β β
β βββ PluginBridgeEditor β
β β βββ PluginPickerComponent β manufacturer TreeView + searchβ
β β βββ pluginEditor β hosted plugin's own editor β
β β β
β βββ HelperConnection β IPC + shared memory to Helperβ
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Unix socket + shared memory
βΌ
ββ PluginBridgeHelper.app (separate process) ββββββββββββββββββββββ
β Bundled in PluginBridge.vst3/Contents/Resources/ β
β β
β Modes: β
β --load <path> Load plugin, route audio via shared memory β
β --scan <path> Test-load plugin, exit 0=safe / crash=unsafe β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Plugin Load Flow
User selects plugin in picker
β
βΌ
loadPlugin() checks PluginSafetyDB
β
ββββββ΄βββββββββββββββββββ
β β
Unknown Safe/Unsafe already known
β β
βΌ β
Wait for Helper to exit β
Spawn: Helper --scan β
β β
Crashed? β mark Unsafe β
Exit 0? β mark Safe β
β β
ββββββββββββββ¬βββββββββββ
β
βββββββββ΄βββββββββ
β β
Safe Unsafe
β β
βΌ βΌ
Helper --load Helper --load
(audio routing) (audio routing)
β β
βΌ βΌ
loadInProcess() showAudioOnlyUI()
createEditor() (MCP still works)
embed in window
Key constraint: Only ONE Helper process at a time. Scanner must wait for live Helper to finish before spawning a scan subprocess (same shared memory name β conflict).
File Structure
pluginbridge/
βββ CMakeLists.txt
βββ JUCE/ (git submodule)
βββ libs/
β βββ httplib.h (MIT, header-only HTTP server)
β βββ json.hpp (MIT, header-only JSON)
βββ Source/
β βββ Plugin/ β VST3/AU (runs inside Ableton)
β β βββ PluginBridgeProcessor.h/.cpp β main logic
β β βββ PluginBridgeEditor.h/.mm β editor window
β β βββ PluginPickerComponent.h/.mm β plugin browser UI (new v0.5)
β β βββ HelperConnection.h/.cpp β IPC + shared memory
β β βββ McpServer.h/.cpp β HTTP MCP server
β β βββ PluginSafetyDB.h β safe/unsafe JSON DB
β β βββ Blocklist.h β persistent crash blocklist
β β βββ PBLog.h β timestamped logger
β βββ Helper/ β Standalone exe (separate process)
β β βββ main.cpp β --load and --scan modes
β β βββ HelperPluginHost.h/.mm
β β βββ HelperIPC.h/.cpp
β βββ Shared/
β βββ SharedAudioBuffer.h β shared memory layout
β βββ IPCProtocol.h β JSON message formats
β βββ Constants.h
βββ CLAUDE.md β this file
βββ MACHINE-CONTEXT.md β system paths, verified APIs, plugin behaviors
βββ SYNC.md β what was built/fixed and when
βββ FAILED-APPROACHES.md β what didn't work and why
βββ ROADMAP.md
Build
cd "/Volumes/T7 Shield/Users/Aditya/Downloads/AI MUSIC PRODUCTION/pluginbridge/build"
cmake --build . --target PluginBridge_VST3 -- -j4
# Auto-installs to ~/Library/Audio/Plug-Ins/VST3/PluginBridge.vst3
Two targets:
PluginBridge_VST3β builds + installs both plugin and HelperPluginBridgeHelperβ Helper standalone only
CMake 3.28 required (system CMake 4.x incompatible with JUCE 8).
Key Runtime Data
| File | Purpose |
|---|---|
~/Library/PluginBridge/safety_db.json |
Safe/unsafe status per plugin path+mtime |
~/Library/PluginBridge/debug.log |
Session-tagged timestamped log |
~/Library/PluginBridge/scan.log |
Background scan output |
~/Library/PluginBridge/blocklist.txt |
Plugins that crashed Helper during use |
PluginPickerComponent (v0.5)
Source/Plugin/PluginPickerComponent.h/.mm
Entrystruct:{ file, name, manufacturer, blocked, safety }- Callbacks:
onPluginSelected,onClose,onClearBlocklist,onClearSafetyCache static constexpr int kWidth = 420, kHeight = 500- Tree:
ManufacturerTreeItem(folder) βPluginTreeItem(leaf, 24px height) - Safety badges:
Safety::Safeββgreen;Safety::Unsafeβaudio onlyorange;blockedββred - Search:
addChildComponent(searchList)β NOTaddAndMakeVisible(see FAILED-APPROACHES) - Custom
TreeLFLookAndFeel overridesdrawTreeviewPlusMinusBoxfor Ableton-style arrows
JUCE 8 APIs β Verified
Working
formatManager.addFormat(new juce::VST3PluginFormat())formatManager.addFormat(new juce::AudioUnitPluginFormat())plugin->createEditor()β message thread onlyplugin->hasEditor()plugin->getParameters()βArray<AudioProcessorParameter*>juce::MessageManager::callAsync(lambda)β cross-thread UI updatesaddChildComponent(comp)β adds hidden; use instead ofaddAndMakeVisiblewhen starting invisiblejuce::TreeView+juce::TreeViewItemwith customLookAndFeeljuce::File::findChildFiles(findDirectories, false, "*.vst3")
Broken β Do NOT Use
- β
addDefaultFormats()β deleted in JUCE 8 - β
juce::Thread::setCurrentThreadPriority()β removed, use native pthread - β
getParameter(int)/setParameter(int, float)β deprecated - β
getStringWidth()β usegetStringWidthFloat() - β
juce::Rectangle<float>::getTransformToFit()β does not exist - β
juce::Array<CustomStruct>initializer list β usestd::vector<CustomStruct>
macOS Gotchas
- β
MSG_NOSIGNALβ Linux only βsignal(SIGPIPE, SIG_IGN)+SO_NOSIGPIPE - β Two processes with same
shm_openname β both crash β scanner must wait for Helper - β
addAndMakeVisible(comp)aftercomp.setVisible(false)βaddAndMakeVisibleforces visible, invisible comp sits on top intercepting all mouse events β useaddChildComponent(comp)instead - β
CAContext+CALayerHostfor cross-process GUI β doesn't work in Ableton (see FAILED-APPROACHES #10) - β
posix_spawnβ safe for spawning from plugin process - β
shm_open/mmapβ reliable cross-process shared memory
MCP Protocol
- Endpoint:
POST http://127.0.0.1:16620/mcp - Health:
GET http://127.0.0.1:16620/health - Wire format: JSON-RPC 2.0
- Tools:
list_plugins,search_param,get_params,set_params,get_analysis
What NOT To Do
- Don't load plugins in-process without safety scan β crash-prone plugins (iZotope, some Waves) call
abort()and kill Ableton - Don't use
PluginDirectoryScannerβ triggers plugin code on scan β crash - Don't spawn Helper --scan while live Helper is running β shared memory conflict β false UNSAFE results
- Don't use
addAndMakeVisibleon a component that should start hidden β useaddChildComponent - Don't try CAContext/CALayerHost for cross-process GUI β see FAILED-APPROACHES #10