# Live params, modulation and observability

Every Faust UI element in your source is live twice over: as a knob in the
module panel, and as a param path for actions.

- `dsp.param.set { module_id, path, value }` — push a value into the
  running worklet. Paths are the literal Faust addresses from `documents.list`
  (e.g. `/MyDsp/cutoff`). No-op when stopped.
- `dsp.param.get { module_id, path }` — read the **live, post-modulation**
  value the knob currently shows. (Poly magic params are the exception —
  see the MIDI section.)

## Being modulated

A running DSP's params register as modulation **sinks** — any LFO or
modulation source in the Patchbay can drive them. Modulation is
non-destructive: the engine computes `clamp(base + Σ amount × source)`, so
removing an edge restores your base value. Depth lives on the edge
(`routing.connect { kind: "modulation", amount }` / `routing.set`).

## Being a modulator

Tag a bargraph with the `[modout]` metadata and your DSP becomes a
modulation **source** — DSP A's envelope follower can wobble DSP B's
filter:

```faust
process = sig <: _, (an.amp_follower(0.05) : hbargraph("env [modout]", 0, 1) : !);
```

Every `[modout]` output appears as a source port in the Patchbay while the
DSP runs.

## Watching without eyes

- `documents.list` — runtime state of every open DSP (status, compile error,
  params, `polyphonic`, `midi_channel`).
- `system.state { sections: ["master"] }` — master meters (read them while
  sound plays — see *Hearing is proof*).
- `logs.get { level: "error" }` — the renderer log; compile and runtime
  failures the UI shows land here too.

> 🟦 **KB BEFORE CODE**: when writing Faust, query the local knowledge base
> first — `kb.search { corpus: "faust", query: "..." }` returns the actual
> stdfaust signatures from YOUR installed version. Library functions drift;
> the local corpus doesn't lie.
