Map: prompt-to-chain in the plugin#1
Destination
A hand-off-ready spec for prompt-to-chain in the SemantiFX plugin: the user types a target prompt, the Python worker assembles an effect chain with TypeSafe Jev from a catalogue that has grown past EQ and distortion, the plugin shows the chain and optimizes it eagerly while the user can still edit it, and the optimizer runs any chain the catalogue can express. Every decision needed to start building is locked; building itself is a later effort.
Notes
- Domain vocabulary is in
CONTEXT.md. Chain assembly (which effects, how many, what order) is distinct from chain optimization (parameters of a fixed chain). Use those terms. - Skills:
grilling+domain-modelingfor decision tickets;researchfor anything outside the repo;prototypefor state-model or UX questions. Anything verifiable gets built by a Luna subagent from a written spec. - Settled before charting (2026-09-16), not re-litigated here:
- Jev is the assembly planner. Benchmark write-up:
docs/experiments/2026-09-16-jev-planner-benchmark.md. Keep policy and thresholds in code; rich two-sentence effect descriptions in state; no persona text; question wording is a threshold knob, not an accuracy lever. - A CLAP-derived text description of the source audio is dropped. Measured on 2026-09-16: swapping the source string between guitar, vocal, and mix changed no chain and moved probabilities by a few hundredths. Revisit only if the catalogue gains source-dependent effects.
- Jev calls run in the Python worker, not the plugin. The key stays out of the plugin.
- UX flow: assemble, show, optimize eagerly; the user can edit the chain during optimization and the optimizer restarts.
- Optimizer generalization is in scope: it must run whatever chain assembly produces.
- Jev is the assembly planner. Benchmark write-up:
- Every new effect type needs a differentiable Python implementation for the optimizer and a matching C++ implementation in the plugin, with parity tests. That constraint shapes the catalogue.
- Solo repo, work on
main, no PRs. Current prototype:inference/src/semantifx_inference/assembly.pyandinference/diagnostics/jev_chain_assembly.py. - Standing preference (Oliver, 2026-09-16): the agent decides internals (protocol shapes, code generation, validation, initialization, transport) and records them on the ticket without a grill. Oliver is asked only about user interaction and high-level architecture. Tickets whose question is internal are worked by the agent alone; prototypes are built by Luna from a spec and only their outcome is reported. Goal is a working prototype, not a fully locked spec.
Decisions so far
- Research: differentiable effects available to the optimizer and their C++ tractability — only compressor and reverb are new differentiable candidates (plus trivial gain); dasp compressor ignores release and NaNs at zero knee, EQ has zero cutoff/Q gradient at 0 dB, reverb needs a frozen noise table for C++ parity; recommended order gain, compressor, reverb. Findings on
research/differentiable-effects. - Research: TypeSafe Jev limits, pricing, and key distribution constraints — cost is negligible, but the only credential is a full-account key, access is waitlisted, limits are unpublished; developer-only now, proxy is the only future distribution path. Findings on
research/typesafe-limits. - Which effect types join the catalogue, and in what order — catalogue is EQ, distortion, compressor, reverb; reverb first, then compressor; gain out. Compressor is dasp's design trimmed (no release, knee floored above zero); reverb uses a macro parameter layer over dasp's 25. Jev descriptions for both are on the ticket.
- Prototype: build the optimizer's DSP graph from an arbitrary chain list — one type-keyed catalogue (specs, Jev description, render fn) replaces the instance-keyed schema;
instance_idis opaque to the worker andeffect_typeselects the definition; result entries follow chain order. Fixed pair renders bit-identically. Prototype onprototype/variable-chain-optimizer. - Protocol: the assemble request and variable chains end to end — separate
assemblerequest returning a chain in the analyze chain shape plus judgments; analyze validates any catalogue chain (unique ids, known type, complete in-range parameters, 0 to 8 long) under oneinvalid_requestcode; specs reach the plugin via a type-keyedscripts/gen; restart is latest-request-wins with the stop marker kept for plain cancel. - Key handling: developer-only behind a swappable transport for this spec — developer-only, key from
.envread by the worker; onePlannerprotocol with Jev and mock implementations, a proxy later is a third; any failure isassembly_unavailable, the plugin keeps its chain and shows the message, no silent default chain. - Parameter initialization for newly assembled effect instances — new instances start from TOML defaults (gradient hazards handled in the defaults: flat EQ moves gain first, compressor knee default sits above its floor); surviving instances keep current values via
init: current, which makes restart a warm start. - Assembly policy: what the plugin does on a no-change verdict — on a no-change verdict the plugin keeps the current chain and shows a one-line hint, no optimization starts; confidence is not shown in the first prototype, probabilities go to the debug log; threshold 0.4 with argmax fallback, gate 0.5, ties by catalogue order, no current-chain state to Jev in single-shot mode.
- Plugin: representing, rendering, and editing a variable chain — fixed pool of two slots per type with chain composition as saved state, not host parameters; one C++ class per type behind a hand-written factory; audio-level parity fixtures rendered from Python; Ozone-style scrollable card rack with bypass, solo, remove, drag and a + card; structure edits restart now, knobs on release; snapshots are audible as they arrive; Stop keeps, Revert restores the pre-run state; fresh instance starts empty.
- Cut 2026-09-17 (Oliver: cut further): assembly policy (#5) shrunk to one user-facing question, threshold and tie-break and single-shot state decided by the agent on the ticket; the reverb (#10) and compressor (#12) prototypes closed into the build effort.
Not yet specified
- Nothing. Every ticket is closed as of 2026-09-18; the way to the destination is clear and the next step is the build effort, starting from Decisions so far. First build task: record the slot-pool choice from #8 as the first ADR under
docs/adr/.
Out of scope
- Reverb and compressor DSP prototypes as map tickets. Cut 2026-09-17; Luna builds both during the build effort from a spec with parity tests as the acceptance check.
- Threshold calibration and end-to-end evaluation. Build-time work once the four-type catalogue runs live, not a spec decision; calibration note lives on #5.
- Multi-turn refinement (InstructFX2FX's init/reuse/mixed routing). A second map once single-shot prompt-to-chain works.
- Distortion DSP quality. Orthogonal to assembly; track separately.
- CLAP-derived source description as Jev state. Dropped 2026-09-16 on measurement, see Notes.
- Replacing Jev with a custom on-device classifier. Only worth revisiting once there is training data from real use.