robbert-vdh/nih-plug
Rust VST3 and CLAP plugin framework and plugins - because everything is better when you do it yourself
Healthy across the board
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ⚠Concentrated ownership — top contributor handles 76% of recent commits
- ⚠Scorecard: default branch unprotected (0/10)
- ✓Last commit 1d ago
- ✓12 active contributors
- ✓ISC licensed
- ✓CI configured
- ✓Tests present
Computed from maintenance signals — commit recency, contributor breadth, bus factor, license, CI, tests, cross-checked against OpenSSF Scorecard
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/robbert-vdh/nih-plug)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card
This card auto-renders when someone shares https://repopilot.app/r/robbert-vdh/nih-plug on X, Slack, or LinkedIn.
Ask AI about robbert-vdh/nih-plug
Grounded in the actual source code. Pick a starter question or write your own.
Onboarding doc
Onboarding: robbert-vdh/nih-plug
Generated by RepoPilot · 2026-06-24 · Source
🎯Verdict
GO — Healthy across the board
- Last commit 1d ago
- 12 active contributors
- ISC licensed
- CI configured
- Tests present
- ⚠ Concentrated ownership — top contributor handles 76% of recent commits
- ⚠ Scorecard: default branch unprotected (0/10)
<sub>Computed from maintenance signals — commit recency, contributor breadth, bus factor, license, CI, tests, cross-checked against OpenSSF Scorecard</sub>
⚡TL;DR
NIH-plug is a Rust-based VST3 and CLAP audio plugin framework that provides a stateful, API-agnostic abstraction layer for building desktop audio plugins without boilerplate. It ships with a collection of production audio plugins (Buffr Glitch, Crisp, Crossover, Diopser, Spectral Compressor) and integrates multiple UI frameworks (egui, iced, vizia) to handle cross-platform plugin GUIs. Monorepo workspace with core framework at root (src/ likely in parent), derive macros in nih_plug_derive/, UI frameworks in separate crates (nih_plug_egui/, nih_plug_iced/, nih_plug_vizia/), build tooling (xtask/, cargo_nih_plug/), and production + example plugins under plugins/ (plugins/examples/, plugins/soft_vacuum/, plugins/buffr_glitch/, etc.). Workspace members in Cargo.toml with resolver = "2".
👥Who it's for
Audio plugin developers and Rust enthusiasts building VST3/CLAP plugins who want to skip the low-level plugin SDK ceremony while maintaining full control over DSP and UI patterns. Both plugin authors (using nih_plug_derive, nih_plug_egui, nih_plug_iced) and framework contributors.
🌱Maturity & risk
The project is in maintenance mode according to the README, with the core framework stable but no longer the primary focus; documentation is comprehensive at https://nih-plug.robbertvanderhelm.nl/, CI/CD is robust (build, test, docs workflows present), but the note recommends checking the community fork at codeberg.org/BillyDM/nih-plug for active development. Real plugins ship as working binaries.
Single maintainer (Robbert van der Helm) with maintenance-mode status; VST3 SDK legal/licensing constraints mean some features are behind feature gates; the README warns that the framework itself isn't actively developed, suggesting stability over cutting-edge features. Dependencies on baseview, cpal, jack, midir for standalone builds add surface area but are optional behind the standalone feature.
Active areas of work
The project is in maintenance mode — primary development is paused. The community is directed to the BillyDM/nih-plug fork for active work. CI workflows (build.yml, test.yml, docs.yml) suggest the existing codebase is kept green, but no major feature work is visible.
🚀Get running
git clone https://github.com/robbert-vdh/nih-plug.git
cd nih-plug
cargo build --release
# To build a specific plugin:
cargo build -p buffr_glitch --release
# To run tests:
cargo test
Daily commands:
Development: cargo build (builds framework); cargo build -p <plugin_name> for individual plugins. Testing: cargo test. Plugins build to VST3/CLAP bundles in target/. For standalone: cargo build --features standalone -p <plugin_name>.
🗺️Map of the codebase
nih_plug_derive/src/lib.rs— Core procedural macro for parameter and enum derivation; all plugin parameter definitions depend on thisnih_plug_egui/src/editor.rs— egui editor backend integration; reference implementation for UI framework integration patternnih_plug_vizia/src/editor.rs— Vizia editor backend; demonstrates cross-platform declarative UI pattern and window managementcargo_nih_plug/src/main.rs— Custom Cargo subcommand entry point; essential build/bundling tool for plugin compilationnih_plug_xtask/src/lib.rs— Build system utilities and symbol handling for VST3/CLAP plugin wrapper generationCargo.toml— Workspace root configuration defining all plugin framework and example cratesbundler.toml— Plugin bundling configuration; controls VST3/CLAP artifact generation and deployment
🧩Components & responsibilities
- nih_plug_derive (Procedural Macros) (Rust syn/quote, proc_macro2) — Generate Params struct implementations with serialization, UI metadata, and binding code from declarative attributes
- Failure mode: Macro expansion errors prevent compilation; incorrect derive attributes lead to silent parameter drops
- Plugin Trait & Context (Rust async where needed, lock-free queues for param updates) — Abstract interface for audio processing, parameter updates, and editor lifecycle; agnostic to VST3/CLAP details
- Failure mode: Blocking calls in process() cause audio dropouts; missing parameter snapshot corrupts MIDI/automation
- VST3/CLAP Wrapper Layer (vst3-sys, clap-sys raw bindings) — Translate host protocol callbacks into Plugin method calls; enforce real-time safety constraints; serialize state blobs
- Failure mode: Unsafe FFI errors cause host crashes;
🛠️How to make changes
Add a new plugin to the collection
- Create plugin crate directory under plugins/ with Cargo.toml (reference plugins/crisp/Cargo.toml) (
plugins/my_plugin/Cargo.toml) - Implement Plugin trait in src/lib.rs, use nih_plug_derive for Params struct (
plugins/my_plugin/src/lib.rs) - Add plugin crate to workspace members in root Cargo.toml (
Cargo.toml) - Add bundler configuration entry to bundler.toml for VST3/CLAP packaging (
bundler.toml)
Add a custom editor UI using a different framework
- Create new framework crate nih_plug_myui/ with Cargo.toml modeled on nih_plug_vizia/Cargo.toml (
nih_plug_myui/Cargo.toml) - Implement Editor trait and editor context handling (reference nih_plug_egui/src/editor.rs) (
nih_plug_myui/src/editor.rs) - Create widget utilities for param_slider and generic_ui following nih_plug_vizia/src/widgets/ pattern (
nih_plug_myui/src/widgets/param_slider.rs) - Add new framework crate to workspace members in root Cargo.toml (
Cargo.toml)
Add a new parameter type or derive attribute feature
- Extend Params derive macro in nih_plug_derive/src/params.rs with new attribute handling (
nih_plug_derive/src/params.rs) - Add test case in nih_plug_derive/tests/params.rs to validate macro expansion (
nih_plug_derive/tests/params.rs) - Update example plugin to demonstrate new parameter type (e.g., plugins/crisp/src/lib.rs) (
plugins/crisp/src/lib.rs)
🔧Why these technologies
- Rust + Procedural Macros (syn/quote) — Type-safe parameter definitions with zero-cost abstractions; derive macros eliminate boilerplate while maintaining compile-time verification
- Multiple UI frameworks (egui, Vizia, iced) — Allows plugin developers to choose UI toolkit matching their needs; decoupled from core plugin logic via Editor trait
- VST3 and CLAP support via wrappers — Dual plugin standard support; framework abstracts protocol details while plugins remain API-agnostic
- Custom Cargo subcommand (cargo_nih_plug) — Streamlined plugin-specific build operations (bundling, code generation) without custom build scripts in each plugin
⚖️Trade-offs already made
-
API-agnostic plugin interface (VST3/CLAP abstracted away)
- Why: Simplifies plugin development and experimentation; reduces ceremony
- Consequence: Some protocol-specific features may be harder to expose; requires wrapper layer maintenance for spec updates
-
Multiple UI framework support maintained in parallel
- Why: Flexibility for developers with different UI preferences
- Consequence: Increased maintenance burden; widget implementations must stay synchronized across egui/Vizia/iced
-
Framework currently in maintenance mode (per README)
- Why: Original author has limited capacity; directs new development to community fork
- Consequence: New feature velocity reduced; encourages users to contribute upstream or use fork
🚫Non-goals (don't propose these)
- Real-time audio synthesis engine (framework, not DAW)
- Multi-platform GUI abstraction beyond provided frameworks
- Built-in metering, visualization, or advanced DSP library
- Backwards compatibility guarantees during pre-1.0 phase
🪤Traps & gotchas
VST3 SDK licensing: VST3 is behind a feature gate; some builds may require accepting Steinberg's license. Allocation tracking: assert_process_allocs feature causes panics in DSP on unexpected heap allocations (useful but can obscure other panics). macOS Gatekeeper: README warns binaries may need Gatekeeper disabled. No native MIDI on Windows: jack, midir are Linux/macOS; Windows MIDI support requires different approach. UI framework choice is baked in: egui, iced, vizia are separate crates; mixing UIs in same plugin requires custom wrapper work.
🏗️Architecture
💡Concepts to learn
- VST3 Plugin Wrapper — NIH-plug exports VST3 via the
nih_export_vst3!()macro; understanding how Rust trait bounds map to C++ COM interfaces is critical for debugging plugin instantiation and DAW compatibility - CLAP (Common Language Audio Plugin) — The newer plugin format nih-plug supports alongside VST3; CLAP's host callback design differs from VST3's discrete events, affecting parameter modulation and preset handling
- Procedural Macros (Derive Macros) — nih_plug_derive generates boilerplate for parameter binding and enum serialization; understanding macro expansion (in lib.rs, params.rs, enums.rs) is essential for extending the framework or debugging macro errors
- Real-time Audio DSP Constraints — The
assert_process_allocsfeature and process() function design enforce no-allocation rules in the DSP thread; violating this causes latency spikes and dropouts in live playback - Audio Buffer Ring/Circular Buffers — Buffr Glitch uses circular buffers for sample-accurate MIDI-triggered repeats; understanding buffer wrap-around and period-accurate sampling is essential for understanding this plugin
- Feature Gates & Conditional Compilation — nih-plug uses Cargo features (vst3, standalone, assert_process_allocs) extensively to enable/disable large dependency chunks; incorrect feature combinations can cause link-time failures
- Workspace Monorepo Pattern — The Cargo workspace with resolver = "2" manages core framework, derive macros, UI frameworks, and plugins all in one tree; understanding shared dependencies and version pinning across members is critical for local development
🔗Related repos
BillyDM/nih-plug— Active community fork at codeberg.org — this is where NIH-plug development continues post-maintenance-modefree-audio/clap— CLAP plugin standard that nih-plug wraps; essential to understand the wire protocolsteinbergmedia/vst3sdk— VST3 SDK that nih-plug abstracts over; defines the C++ ABI and plugin formatrobbert-vdh/nih-plug-template— Cookiecutter template for scaffolding new NIH-plug projects mentioned in README; shows idiomatic plugin structureDioxusLabs/dioxus— Alternative Rust UI framework ecosystem (not currently integrated but relevant for future plugin UI experiments)
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive integration tests for nih_plug_derive macro expansion
The nih_plug_derive crate (nih_plug_derive/src/lib.rs, enums.rs, params.rs) has only basic tests in nih_plug_derive/tests/. Given that derive macros are critical to the framework's usability and correctness, there should be expanded tests covering edge cases: nested parameter structures, all parameter types with derive attributes, persistence serialization round-trips, and macro error messages. This directly impacts plugin developers' experience.
- [ ] Add tests in nih_plug_derive/tests/ for nested struct parameter derivation
- [ ] Add tests for all parameter type combinations (Int, Float, Bool, Enum) with various attributes
- [ ] Add round-trip serialization tests in nih_plug_derive/tests/persist.rs for complex parameter structures
- [ ] Add tests validating helpful compile-time error messages for invalid derive usage
Implement platform-specific CI workflow validations for GUI frameworks
The repo supports three GUI frameworks (egui, iced, vizia) across multiple platforms, but .github/workflows/build.yml likely doesn't test all framework combinations on all platforms. Given the complexity of GUI rendering across Windows/macOS/Linux and the framework-specific dependencies, adding targeted workflows that validate each GUI framework builds correctly on each platform would catch regressions early and improve reliability for plugin developers choosing a GUI backend.
- [ ] Review .github/workflows/build.yml to identify missing platform-framework combinations
- [ ] Create a new matrix-based workflow testing nih_plug_egui, nih_plug_iced, and nih_plug_vizia on ubuntu-latest, windows-latest, and macos-latest
- [ ] Add workflow steps to build example plugins (gain_gui_egui, gain_gui_iced, gain_gui_vizia) on each platform
- [ ] Document expected build outputs in .github/workflows/readme-*.txt files
Add missing documentation for standalone plugin export feature and JACK/CoreAudio integration
The Cargo.toml shows a 'standalone' feature that enables baseview, clap, cpal, jack, and midir dependencies, but there's no dedicated documentation explaining how to use nih_export_standalone!() or how JACK/CoreAudio integration works. Plugin developers need clear guidance on building cross-platform standalone binaries. This should include platform-specific notes in nih_plug_egui/README.md, nih_plug_iced/README.md, and nih_plug_vizia/README.md.
- [ ] Add 'Standalone Export' section to main README.md with nih_export_standalone!() usage example
- [ ] Document the standalone feature dependencies and their platform availability (JACK on Linux, CoreAudio on macOS, etc.)
- [ ] Add platform-specific build instructions in each GUI framework's README (nih_plug_egui/README.md, etc.) for standalone targets
- [ ] Add a minimal standalone example plugin or update existing examples to document standalone export
🌿Good first issues
- Add automated tests for nih_plug_derive/src/params.rs covering edge cases in macro expansion (optional params, nested structs, unit variants) — tests/params.rs exists but is minimal
- Document the parameter persistence format (likely YAML/JSON serialization) in a markdown guide under docs/ since bundler.toml and preset handling are not well-explained in README
- Create a Windows MIDI example plugin (plugins/examples/ has sysex but no Windows MIDI I/O) showing how to work around the lack of jack/midir on Windows using std library or winapi
⭐Top contributors
Click to expand
Top contributors
- @robbert-vdh — 76 commits
- @BillyDM — 8 commits
- [@Billy Messenger](https://github.com/Billy Messenger) — 4 commits
- @andrewprograms — 2 commits
- @oilcake — 2 commits
📝Recent commits
Click to expand
Recent commits
f36931f— Fix doc generation (robbert-vdh)59c18bf— Reformat with rustfmt (robbert-vdh)28f52b9— Update use of night SIMD API (robbert-vdh)60e3f52— Link to a community fork of the framework (robbert-vdh)28b149e— Fix wrong date in changelog (robbert-vdh)51a5db1— Merge branch 'andrewprograms/master' #230 (robbert-vdh)206834c— Fix warning "hiding a lifetime that's elided elsewhere" (andrewprograms)376d8d4— Fix for Issue #220 (andrewprograms)ecfd632— Make implicit autorefs explicit in buffer code (robbert-vdh)7da01b5— fix transparency in softbuffer example (BillyDM)
🔒Security observations
The nih-plug codebase appears to be a well-structured Rust audio plugin framework with generally good security practices. The project is written in Rust, which provides memory safety guarantees. No critical vulnerabilities were identified in the visible configuration. Main areas for improvement include: (1) establishing a formal security policy and vulnerability disclosure process, (2) ensuring regular dependency audits are performed, (3) enabling or defaulting to real-time safety features like allocation assertions in debug builds, and (4) maintaining up-to-date Rust version requirements. The framework's focus on stateless, simple APIs suggests good architectural security design for audio plugin development.
- Medium · Outdated Rust MSRV —
Cargo.toml (root). The project specifies rust-version = '1.80' which may be outdated depending on current date. Older Rust versions may contain known security vulnerabilities in the standard library and compiler. Fix: Regularly update the MSRV to a recent stable Rust version and test compatibility. Consider using a CI check to ensure builds work with the specified MSRV. - Medium · Optional Security-Critical Features —
Cargo.toml (root) - features section. The 'assert_process_allocs' feature for detecting allocations during DSP processing is not enabled by default. This feature helps catch memory allocation issues that could affect real-time audio processing safety, but users must explicitly enable it. Fix: Consider making 'assert_process_allocs' default for debug builds, or provide clear documentation and examples showing how to enable it for development. Add warnings in documentation about real-time safety. - Low · Incomplete Repository Information —
Cargo.toml (root) - version field. The Cargo.toml shows version '0.0.0' which is non-standard for a published package. This may indicate the package is pre-release or has unconventional versioning that could cause dependency resolution issues. Fix: Use semantic versioning (e.g., 0.1.0 or higher) to clearly indicate the stability and maturity of the package. Update version consistently for releases. - Low · Workspace Member Documentation —
Cargo.toml (root) - dependencies. Multiple optional feature dependencies (baseview, clap, cpal, jack, midir, rtrb) are listed but no dependency versions are visible. Without seeing the actual Cargo.lock or dependency versions, supply chain risks cannot be fully assessed. Fix: Audit all transitive dependencies using 'cargo audit' regularly. Consider using cargo-deny or cargo-supply-chain to maintain a dependency security policy. Lock to specific versions for production releases. - Low · No Security Policy Visible —
Repository root. No SECURITY.md file is visible in the repository structure, which means there is no documented security disclosure policy for researchers finding vulnerabilities. Fix: Create a SECURITY.md file documenting how to responsibly report security vulnerabilities (e.g., private disclosure process, security@domain.com contact).
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/robbert-vdh/nih-plug shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live robbert-vdh/nih-plug
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/robbert-vdh/nih-plug.
What it runs against: a local clone of robbert-vdh/nih-plug — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in robbert-vdh/nih-plug | Confirms the artifact applies here, not a fork |
| 2 | License is still ISC | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 31 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of robbert-vdh/nih-plug. If you don't
# have one yet, run these first:
#
# git clone https://github.com/robbert-vdh/nih-plug.git
# cd nih-plug
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of robbert-vdh/nih-plug and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "robbert-vdh/nih-plug(\\.git)?\\b" \\
&& ok "origin remote is robbert-vdh/nih-plug" \\
|| miss "origin remote is not robbert-vdh/nih-plug (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(ISC)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"ISC\"" package.json 2>/dev/null) \\
&& ok "license is ISC" \\
|| miss "license drift — was ISC at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "nih_plug_derive/src/lib.rs" \\
&& ok "nih_plug_derive/src/lib.rs" \\
|| miss "missing critical file: nih_plug_derive/src/lib.rs"
test -f "nih_plug_egui/src/editor.rs" \\
&& ok "nih_plug_egui/src/editor.rs" \\
|| miss "missing critical file: nih_plug_egui/src/editor.rs"
test -f "nih_plug_vizia/src/editor.rs" \\
&& ok "nih_plug_vizia/src/editor.rs" \\
|| miss "missing critical file: nih_plug_vizia/src/editor.rs"
test -f "cargo_nih_plug/src/main.rs" \\
&& ok "cargo_nih_plug/src/main.rs" \\
|| miss "missing critical file: cargo_nih_plug/src/main.rs"
test -f "nih_plug_xtask/src/lib.rs" \\
&& ok "nih_plug_xtask/src/lib.rs" \\
|| miss "missing critical file: nih_plug_xtask/src/lib.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 31 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~1d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/robbert-vdh/nih-plug"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.
Embed this chat in your README →
Drop this iframe anywhere — the widget runs against the same live analysis cache as the main app.
<iframe src="https://repopilot.app/embed/robbert-vdh/nih-plug" width="100%" height="500" style="border:1px solid #d0d7de; border-radius:8px;" allow="microphone" loading="lazy" ></iframe>