codex export

Build VST3 and standalone targets from your manifest, plus platform requirements and what lands in build/.

The codex CLI is proposed, not yet shipped. This page describes the intended command surface; today the equivalent steps run through the workspace scripts and plugin-shell-kit generate directly.

Usage

npx codex export vst3
# → build/MyPedal.vst3
# → build/MyPedal.app  (standalone, same kernel)

Two artifacts, one command. The .vst3 is the plugin you drop in your plugins folder; the .app is a standalone macOS host that opens your UI over a CoreAudio device and runs the identical kernel, which makes it the fastest way to check a build without launching a DAW.

What actually happens

No magic, so here is the pipeline in full.

  1. Your manifest is read. plugin.config.json names the plugin, its vendor, its category, which kernel to compile, and where your built web UI lands.
  2. The kernel is compiled twice from one source — freestanding WASM for the browser worklet, and a native library for the plugin. Same TypeScript, same math, same state layout.
  3. @codex-music/plugin-shell-kit generates the shell. From your schema it emits the VST3 parameter table with stable indices, so automation survives version bumps; the state-chunk codec that saves and restores your patch inside a session; the codexHost bridge JS injected before your bundle loads; and the CMake targets.
  4. CMake builds the native shell, embedding the compiled kernel as the processor and your web UI bundle as the plugin editor.

Step 3 is worth pausing on, because it is what makes step 4 generic. There is one shell, reused by every plugin, parameterized entirely by your manifest and schema. The VST3 class ids are derived deterministically from your plugin id — same id, same ids, every regeneration — which is what lets a session saved against one build reopen against the next.

Your manifest

Short, because most of it is derivable:

{
  "id": "music.codex.my-pedal",
  "name": "My Pedal",
  "vendor": "Codex Music",
  "version": "0.1.0",
  "category": "Fx",
  "kernel": {
    "package": "@codex-music/audio-kernels",
    "profile": "profiles/tone-pedal.profile.json",
    "abiPrefix": "sctone_"
  },
  "ui": {
    "dist": "dist-plugin"
  }
}

category is "Fx" or "Instrument". kernel.abiPrefix must match the kernelId in your ParamSchema; the generator fails loudly if they disagree, rather than producing a shell wired to the wrong symbols. ui.dist is the Vite output directory of your plugin-flavored build, bundled into plugin resources and served to the embedded webview through a custom scheme handler.

The schema itself is found automatically at src/schema.ts, with the export detected as the single one shaped like a ParamSchema whose kernelId matches your abiPrefix. If a module exports more than one, add a schema block naming the module and export explicitly.

Platform requirements

V1 is VST3 plus standalone on macOS. That is the shipped scope, not a stylistic preference — it is where the shell, the validator run, and the parity harness are green today.

Exporting needs a native toolchain that the dev and browser loops do not: a C++ compiler, CMake, and the VST3 SDK, which CMake fetches for you. The SDK is dual-licensed GPLv3 or a free proprietary agreement from Steinberg; which one applies to you depends on how you license your plugin, and Licensing covers the interaction.

AU and CLAP are on the roadmap. Because the shell is generated from your manifest, they arrive as a new export target rather than a rewrite of your tool — your kernel, schema, and UI are unchanged, and the format entry point is the only new native code, written once by us and shared by every plugin.

What is real today

The parts this command would wrap already exist and work. The native plugin shell is built and passes the Steinberg VST3 validator. plugin-shell-kit generate is a real CLI that reads a real plugin.config.json, loads your schema, and emits the param table header, the CMake fragment, and a resolved manifest snapshot. There is a verification target that loads the built .vst3 through the VST3 hosting API, replays a golden fixture with a preset chunk and an automation point, renders offline, and byte-compares the result against the offline batch render — including under 512-frame host chunking.

What does not exist yet is the single-command wrapper. Today those steps are run individually through the workspace scripts. See Plugin Shell Kit for the generator as it stands, and Parity and determinism for what the byte-compare guarantees.

When the build is green, codex publish puts it in the directory.