Docker-first web UI + MCP server for Faust prototyping, featuring an Orbit UI for expressive multi-parameter exploration and tight AI-in-the-loop iteration.
Prerequisite: Docker installed and running.
docker run -d \
--name faustforge \
-p 3000:3000 \
-v "$HOME/.faustforge/sessions:/app/sessions" \
-v /var/run/docker.sock:/var/run/docker.sock \
-e SESSIONS_DIR=/app/sessions \
-e HOST_SESSIONS_DIR="$HOME/.faustforge/sessions" \
-e FAUST_HTTP_URL=http://localhost:3000 \
ghcr.io/orlarey/faustforge:latestdocker run pulls the image automatically if it is not present locally.
To force the latest image: docker pull ghcr.io/orlarey/faustforge:latest (or docker run --pull always ... if supported).
Then open:
http://localhost:3000
Notes:
- Sessions are persisted in
~/.faustforge/sessions. SESSIONS_DIRis the in-container path used by faustforge for session storage. It must match the container side of the sessions volume mount (/app/sessions).FAUST_HTTP_URLis the base HTTP URL used by internal components (including MCP in the container) to call the faustforge API./var/run/docker.sockis required because the app launches the Faust Docker image for C++ compilation.HOST_SESSIONS_DIRmust point to the host path of sessions so nested Docker mounts resolve correctly.
Use this mode if you want:
- automatic recompilation when
.dspfiles change on disk - automatic switch to newly discovered
.dspfiles (same behavior as dropping a file in the UI)
docker run -d \
--name faustforge \
-p 3000:3000 \
-v "$HOME/.faustforge/sessions:/app/sessions" \
-v "$HOME/faust-workspace:/workspace" \
-v /var/run/docker.sock:/var/run/docker.sock \
-e SESSIONS_DIR=/app/sessions \
-e HOST_SESSIONS_DIR="$HOME/.faustforge/sessions" \
-e FAUST_HTTP_URL=http://localhost:3000 \
-e LIVE_AUTO_DISCOVER=1 \
-e LIVE_WORKSPACE_ROOT=/workspace \
-e LIVE_SCAN_INTERVAL_MS=1500 \
ghcr.io/orlarey/faustforge:latestThen open:
http://localhost:3000
In this setup, .dsp files under the mounted workspace are discovered automatically.
When a .dsp file appears or is modified, it is auto-opened and becomes the active session.
This matches the helper script default workspace path: $HOME/faust-workspace.
Notes:
LIVE_AUTO_DISCOVER=1enables periodic scan of.dspfiles underLIVE_WORKSPACE_ROOT.LIVE_WORKSPACE_ROOTmust match the container side of the workspace mount (/workspacein this example).LIVE_SCAN_INTERVAL_MScontrols detection/refresh latency (default1500ms).- Use
LIVE_AUTO_DISCOVER=0to disable live workspace behavior.
Optional overrides:
docker run -d \
--name faustforge-dev \
-p 3001:3000 \
-v "$HOME/.faustforge-dev/sessions:/app/sessions" \
-v /var/run/docker.sock:/var/run/docker.sock \
-e SESSIONS_DIR=/app/sessions \
-e HOST_SESSIONS_DIR="$HOME/.faustforge-dev/sessions" \
-e FAUST_HTTP_URL=http://localhost:3001 \
ghcr.io/orlarey/faustforge:latest$sessions = "$env:USERPROFILE\.faustforge\sessions"
New-Item -ItemType Directory -Force -Path $sessions | Out-Null
docker run -d `
--name faustforge `
-p 3000:3000 `
-v "${sessions}:/app/sessions" `
-v /var/run/docker.sock:/var/run/docker.sock `
-e SESSIONS_DIR=/app/sessions `
-e HOST_SESSIONS_DIR="$sessions" `
-e FAUST_HTTP_URL=http://localhost:3000 `
ghcr.io/orlarey/faustforge:latestThen open http://localhost:3000.
Open http://localhost:3000. The first thing before using FAUSTFORGE is to enable audio by clicking the Enable Audio button. This step is required because web browsers block audio playback until the user explicitly allows it (Web Audio API security policy).
Once audio is enabled, you can start creating sessions by dropping Faust files.
A session is a Faust .dsp code associated with different views, including a run view where you can listen to and interact with the audio application.
In order to create a session you can:
- Drop a
.dspfile into the page. - Paste Faust code directly (
Ctrl+V/Cmd+V), which creates aclip-<timestamp>.dspsession.
Note that you can create new sessions from any session and any view. For example, if you are in the block diagram view, you can drop a .dsp file to visualize its block diagram.
When LIVE_AUTO_DISCOVER=1 is enabled and a host folder is mounted to LIVE_WORKSPACE_ROOT:
- Every
.dspfile found under that workspace is tracked as a live session. - Saving changes to a tracked
.dspfile triggers automatic live refresh/recompilation. - Creating or modifying a
.dspfile automatically opens it and makes it the active session (same behavior as dropping a file in the UI). - Live session IDs are stable for a given file path (moving/renaming a file creates a different live session ID).
- Empty live files are treated as draft sessions: compilation is skipped until content is non-empty.
- In draft mode, faustforge forces
dspview and other views are temporarily disabled.
Operational notes:
- Scan cadence is controlled by
LIVE_SCAN_INTERVAL_MS(default:1500ms). - Auto-discovery can be disabled with
LIVE_AUTO_DISCOVER=0. - The regular Refresh button still works and forces regeneration for the currently selected session.
You can navigate between sessions using the left and right arrows, and between views using the up and down arrows or the view menu.
- Sessions:
◀/▶ - Views menu order:
dsp,svg,run,cpp,tasks,signals - Keyboard shortcuts:
←/→: previous/next session↑/↓: previous/next view
The following views let you inspect the Faust source and its generated artifacts:
dsp: original Faust source code.svg: block diagram rendered as SVG.cpp: generated C++ code.tasks: task-level parallelism graph (see section 6).signals: internal signal graph (see section 6).
The run view is covered in detail in the next section.
Go to run view to:
- start/stop audio
- view the produced spectrum or waveform
- interact with controls in
Regular UIandOrbit UI - play notes from the virtual MIDI keyboard in the top bar (
A W S E D F T G Y H U J, octaveZ/X) - use MCP tools against the same active session
Orbit UI is a 2D control space for fast exploration of many parameters at once.
- Each slider is an icon around a central point.
- Slider value depends on icon distance to center:
- on/inside inner disk: maximum
- outside outer circle: minimum
- between both: linear interpolation
- Drag a slider icon: changes only this slider (if active).
- Drag the center: changes all active sliders at once.
- Drag the outer circle ring (
grabcursor): changes outer radius and updates all active sliders. Shift+clickan icon: toggle slider active/disabled.- disabled slider is shown in dark gray
- can move visually, but does not affect DSP parameter
- ignored by center/radius gestures
- ignored by parameter-to-orbit sync
- In polyphonic mode, Orbit auto-disables only sliders matching
freq,gate, orgain.
These two views give access to internal representations used by the Faust compiler:
tasks: task-level parallelism graph generated byfaust -vec -tg. It shows how the compiler splits computation into parallel tasks.signals: signal-level graph generated byfaust -sg. It shows the internal signal expression tree before compilation.
Click the Split view button to show the .dot source code side by side with the rendered graph.
If SVG rendering fails (typically because the graph is too large), faustforge displays an error banner and automatically switches to a DOT-only fallback view where you can still read and download the .dot source.
- Refresh (
↻): regenerates all session artifacts (C++, SVG, graphs) from the current Faust source. Use this after editing the.dspcode. - Download: exports the content of the current view. The exported format depends on the active view:
dsp→<name>.dsp(Faust source)svg→<name>.svg(block diagram)cpp→<name>.cpp(generated C++ code)tasks→<name>-tg.dot(tasks graph in DOT format)signals→<name>-sig.dot(signals graph in DOT format)
- Delete: deletes the current session and all its associated artifacts. The next available session is automatically selected.
- Archive: downloads all sessions as a single
.tar.gzarchive. This is useful for backing up your work or transferring sessions to another machine.
make rebuildmake runThe helper script uses:
PORT(default3000)NAME(defaultfaustforge)HOST_SESSIONS_DIR(default$HOME/.faustforge/sessions)LIVE_AUTO_DISCOVER(optional, default1, set0to disable workspace auto-discovery)LIVE_WORKSPACE_ROOT(optional, default/workspace)LIVE_SCAN_INTERVAL_MS(optional, default1500)LIVE_IGNORE_DIRS(optional CSV list, example:.git,node_modules,build)
You can still use the raw scripts directly:
./scripts/rebuild.sh./scripts/run.sh./scripts/stop.sh
To auto-create/update live sessions from files saved in a mounted workspace:
docker run -d \
--name faustforge \
-p 3000:3000 \
-v "$HOME/.faustforge/sessions:/app/sessions" \
-v "$HOME/faust-workspace:/workspace" \
-v /var/run/docker.sock:/var/run/docker.sock \
-e SESSIONS_DIR=/app/sessions \
-e HOST_SESSIONS_DIR="$HOME/.faustforge/sessions" \
-e FAUST_HTTP_URL=http://localhost:3000 \
-e LIVE_AUTO_DISCOVER=1 \
-e LIVE_WORKSPACE_ROOT=/workspace \
-e LIVE_SCAN_INTERVAL_MS=1500 \
faustforge:latestEdit:
~/Library/Application Support/Claude/claude_desktop_config.json
Add:
{
"mcpServers": {
"faustforge": {
"command": "docker",
"args": ["exec", "-i", "faustforge", "node", "/app/mcp.mjs"]
}
}
}Restart Claude Desktop.
With MCP configured, Claude Desktop can control Faustforge and work on the same sessions as the web UI.
What the AI can do:
- Forge: submit/edit Faust DSP code and inspect generated artifacts.
- Play: switch to
run, start/stop audio transport, and control UI parameters. - Analyze: capture and read spectrum snapshots to evaluate sonic changes.
Typical workflow:
1) get_onboarding_guide()
2) set_view("run")
3) get_run_ui()
4) run_transport("start")
5) set_run_param(...)
6) set_run_param_and_get_spectrum(...)
7) trigger_button_and_get_spectrum(...)
8) analyze series and aggregate.summary
9) iterate on DSP or parameters
Run control tools:
get_onboarding_guide()-> best-practice workflow + thresholds for autonomous AI behaviorget_run_ui-> return Faust UI JSON (parameter paths)get_run_params-> return current run parameters by pathget_polyphony()-> get current polyphony (0means mono)set_polyphony(voices)-> set polyphony (0,1,2,4,8,16,32,64;0means mono)set_run_param(path, value)-> set one continuous parameterset_run_param_and_get_spectrum(path, value, settleMs?, captureMs?, sampleEveryMs?, maxFrames?)-> set parameter + capture spectrum-summary time series + max-hold aggregaterun_transport(action)->start,stop, ortoggletrigger_button(path, holdMs?)-> safe press/release cycletrigger_button_and_get_spectrum(path, holdMs?, captureMs?, sampleEveryMs?, maxFrames?)-> trigger + spectrum-summary time series + max-hold aggregatemidi_note_on(note, velocity?)-> send MIDI note-onmidi_note_off(note)-> send MIDI note-offmidi_note_pulse(note, velocity?, holdMs?)-> send note-on then note-off automaticallymidi_note_on_and_get_spectrum(note, velocity?, settleMs?, captureMs?, sampleEveryMs?, maxFrames?)-> note-on + spectrum-summary time series + max-hold aggregatemidi_note_off_and_get_spectrum(note, settleMs?, captureMs?, sampleEveryMs?, maxFrames?)-> note-off + spectrum-summary time series + max-hold aggregatemidi_note_pulse_and_get_spectrum(note, velocity?, holdMs?, captureMs?, sampleEveryMs?, maxFrames?)-> note-pulse + spectrum-summary time series + max-hold aggregate
Faust library documentation tools:
- The Docker image ships with a prebuilt Faust doc index generated from
faustwasmstdlib (/usr/share/faust/stdfaust.lib). - No runtime fallback: MCP expects this prebuilt index to be present in the image.
search_faust_lib(query, limit?, module?)-> search symbols without loading full docs in contextget_faust_symbol(symbol)-> full symbol entry (summary, usage/signature, params, io withinSignals/outSignalswhen derivable, test snippet, source)list_faust_module(module, limit?)-> list symbols from one module (e.g.delays,filters)get_faust_examples(symbolOrModule, limit?)-> retrieve test/example snippetsexplain_faust_symbol_for_goal(symbol, goal)-> action-oriented guidance for a concrete DSP objective
Spectrum behavior:
- When audio is running in
runview, the frontend pushes compact spectrum summaries to MCP state. get_view_contentreturns spectrum content when current view isrun.get_spectrumreturns the latest spectrum summary independently of current view.- Capture starts at tool call time (only fresh snapshots are aggregated).
- Legacy fallback remains available when summary is not present.
spectrum_summary_v1can includeaudioQualityfeedback for temporal defects:peakDbFSQ,clipSampleCount,clipRatioQ,dcOffsetQ,clickCount,clickScoreQ.
Audio quality quick interpretation (practical thresholds):
clipRatioQ > 1(per-mille) -> clipping is likely audible.clipRatioQ > 5-> severe clipping.clickScoreQ > 20-> potential click/pop artifacts.clickScoreQ > 40-> strong click risk (usually clearly audible).peakDbFSQ >= -1with highclipRatioQ-> limiter/saturation region.
Browser note:
- On page open, faustforge requires an explicit
Enable Audioclick to unlock WebAudio in this tab. - MCP audio tools (
run_transport start/toggle, trigger/capture tools) are blocked until this unlock step is done.
Parameter behavior:
hslider,vslider,nentry: value persists until changed.button: requires a full cycle (1then0) to retrigger correctly.checkbox: toggles between0and1, value persists.
Signals view:
signalsdisplays the Faust signal graph rendered fromsignals.dot(faust -sg).- In
signalsview, Download exports<name>-sig.dot.
make help
make logs
make stopghcr.io/orlarey/faustforge:latest









