Skip to content

wretcher207/reaper-daemon

Repository files navigation

Reaper Daemon

A local file bridge for controlling REAPER from an AI agent — Claude Code, Codex, Cursor's terminal agent, anything that can read and write files. No network, no socket required: the agent drops JSON command files in a folder, a Lua script inside REAPER executes them and writes JSON results back. An optional MCP server (reaper_mcp.py, stdio, same trust model) exposes the whole bridge as tools for Claude Desktop, Claude Code, and any other MCP client — see MCP server below.

Works on macOS, Windows, and Linux. The bridge itself is pure Lua using native REAPER API only (path separators are derived from package.config, so the same script runs everywhere). The agent-facing CLI (reaperd.py) and the MCP server (reaper_mcp.py) are plain Python 3 files with no third-party dependencies.

The bridge is plugin-agnostic and drum-library-agnostic. It ships with no knowledge of any specific synth, amp sim, or instrument. An agent discovers what a project contains with scan_fx, acts on tracks/FX/parameters by name, and can auto-discover a drum kit's note map from the library's own .midnam.

What it does

  • Project control — transport, tempo, cursor, time selection, render.
  • Tracks — add, delete, rename, select, volume, pan, mute, solo, arm, color.
  • FX — add, remove, bypass, reorder, set parameters, write parameter automation envelopes. Any plugin (VST2/3, CLAP, AU, JS).
  • Markers, regions, media items.
  • MIDI — insert MIDI files; a creative drum DSL engine with humanization (velocity model, fatigue, timing jitter).
  • Discoveryscan_fx dumps every FX and parameter; discover_drum_map reads a drum track's note names and builds a kit map for any library.

Every mutating command runs inside a REAPER undo block (Cmd+Z / Ctrl+Z to revert).

How it works

A single runtime: the Lua bridge (bridge/reaper_agent_bridge.lua) runs forever as a reaper.defer loop inside REAPER. It polls inbox/, executes one command per tick, writes results to outbox/, and a heartbeat to bridge/heartbeat.json. This is the only thing that touches the REAPER API.

All JSON writes are atomic (write .tmp, then rename). Command files move inbox/processing/archive/ (ok) or failed/ (error).

Install (cross-platform, one command)

Requires REAPER and Python 3.8+ (no pip packages needed).

git clone https://github.com/wretcher207/reaper-daemon.git
cd reaper-daemon
python3 setup/install.py        # macOS/Linux  (use `python` on Windows)

setup/install.py detects your OS, locates REAPER's per-user resource directory, and writes a marker-delimited block into Scripts/__startup.lua that auto-loads the bridge on every launch, pointing at this clone. It is idempotent — re-run it any time you move the repo. Then (re)start REAPER.

Options:

python3 setup/install.py --dry-run     # preview, change nothing
python3 setup/install.py --uninstall   # remove the managed auto-start block
python3 setup/install.py --bridge-root /path/to/clone
REAPER_RESOURCE_PATH=/custom/dir python3 setup/install.py

Prefer to load it manually instead of at startup? In REAPER: Actions > Show action list > ReaScript: Load…, pick bridge/reaper_agent_bridge.lua, run it once. It runs as a background deferred script and regenerates bridge/bridge_config.json and its working folders on first run.

Install via ReaPack (REAPER-native, alternative)

Prefer REAPER's own package manager? Add this repo to ReaPack:

  1. In REAPER: Extensions > ReaPack > Import repositories.
  2. Paste: https://github.com/wretcher207/reaper-daemon/raw/main/index.xml
  3. Extensions > ReaPack > Browse packages, find Reaper Daemon, install.

Two things to know, because ReaPack delivers only the two Lua files (reaper_agent_bridge.lua + json.lua) — not the agent CLI, the command examples, or the drum engine:

  • It does not auto-start. ReaPack installs the bridge as an Action but does not run it on launch. Run the action once per session, or add it to your Scripts/__startup.lua (python3 setup/install.py from a clone does this for you).
  • You still need the rest of the package. reaperd.py (the agent CLI), commands/examples/, and skills/drum-apparatus/ (the drum DSL engine) are NOT installed by ReaPack. For those, also clone the repo: git clone https://github.com/wretcher207/reaper-daemon.git and point your agent at the clone (or run python3 setup/install.py from the clone, which handles auto-start too). ReaPack then just keeps the bridge script updated.
  • Point your agent at the install folder. ReaPack installs to <REAPER resource>/Scripts/reaper-daemon/. Right-click the package in ReaPack and "Show in explorer/finder" to get the exact path, then aim your agent at that folder.

Verify it

With REAPER open and a project loaded:

python3 reaperd.py status
python3 reaperd.py send commands/examples/get_context.json --wait

status reports the bridge heartbeat; send --wait prints a JSON result describing the open project. If it times out, check that bridge/heartbeat.json exists and is fresh.

The agent CLI — reaperd.py

One Python entry point for everything an agent does (no shell helpers, no jq/grep pipelines — works identically on macOS, Windows, Linux):

python3 reaperd.py status                       # liveness check (run first)
python3 reaperd.py send <cmd.json> --wait       # send a command file
python3 reaperd.py cmd <type> '<payload-json>'  # send by type + payload
python3 reaperd.py fxload "<plugin query>" <track|master>
python3 reaperd.py setparam <track> "<fx>" "<param>" "<display value>"
python3 reaperd.py eq <track> "<fx>" <band> <freqHz> <gaindB> [Q]
python3 reaperd.py groove <beat.dsl> --track Drums [--position SEC] [--map NAME]
python3 reaperd.py jam                          # DSL drum beat from stdin -> selected track
python3 reaperd.py list-maps                    # available drum-kit maps
python3 reaperd.py discover-map <track> [--save <name>]
python3 reaperd.py add-map <name> --file <map.json>   # or --roles '{...}' / stdin
python3 reaperd.py remove-map <name>

fxload and cmd add_fx resolve a fuzzy plugin query to REAPER's exact installed name from the VST/CLAP/AU cache before loading. setparam works on any plugin by parameter index, binary-searching the normalized value that produces a target display value, then verifying.

MCP server — talk to REAPER in plain English

reaper_mcp.py wraps the same file bridge as an MCP stdio server, so any MCP client can drive REAPER conversationally. Zero dependencies, no network listener — it translates tool calls into the same inbox/outbox files, with the same safety semantics (undo blocks, dry_run, risk gating).

Claude Code:

claude mcp add reaper -- python3 /path/to/reaper-daemon/reaper_mcp.py

(Use python instead of python3 on Windows if that's what is on PATH.)

Claude Desktop (claude_desktop_config.json):

{ "mcpServers": { "reaper": {
    "command": "python",
    "args": ["C:/path/to/reaper-daemon/reaper_mcp.py"] } } }

Then just ask: "add a ReaEQ to the bass and carve 2 dB at 300 Hz", "what plugins are on the master?", "program a d-beat groove at bar 33".

18 tools: project/FX discovery (get_context, scan_fx, get_fx_parameters, get_track_routing), transport, tracks, FX chains, set_fx_param (formatted values like "-16.00 dB" work), automation envelopes, markers/regions, MIDI insertion, batch (one undo block), post-FX stem capture, and — with Post Mortem installed — analyze_track / compare_tracks, which hand the calling model measured mix data (LUFS, true peak, spectrum, stereo image, masking table) to diagnose. Mutations are undoable with one Ctrl/Cmd+Z; destructive tools ask the model to confirm intent; audio capture stays behind the allow_risk_level_3 config gate (restart REAPER after changing it).

FX discovery returns REAPER's real track and FX GUIDs alongside names and indices. Use the GUIDs as stable identity when planning a later change: names can be duplicated, and indices move when a user edits the chain. The exact identity fields and compatibility rules are documented in bridge/command_schema.md.

Post Mortem Phase 1 consumes these read-only identities to validate structured recommendations. Reaper Daemon does not preview or apply those recommendations; its existing mutation commands remain explicit, independently authorized bridge operations. Reaper Daemon stays MIT-licensed and local. Planned hosted Post Mortem services or UI do not move this bridge behind a commercial boundary.

Drum kits — any library, auto-discovered

The DSL drum engine (skills/drum-apparatus/) ships a few built-in kit maps (GM Standard, RS Monarch, Odeholm, MDL Tone, Sleep Token II) in skills/drum-apparatus/catalog/maps.json. For any other library, auto-discover:

# 1. With the drum plugin on a track that has its .midnam loaded:
python3 reaperd.py discover-map Drums --save MyKit
# 2. Use it:
python3 reaperd.py groove beat.dsl --track Drums --map MyKit
#    or in the DSL:   @map MyKit

discover-map reads the MIDI note names REAPER has for the track (the .midnam the library installed), classifies each note into a groovekit role (kick / snare / hat-closed / hat-open / ride / crash / china / tom1..4 / ...), fills missing articulations by fallback so a sparse kit never breaks the engine, and saves the result to the user overlay (skills/drum-apparatus/maps/<name>.json, gitignored). Libraries that don't ship a .midnam (some Kontakt kits) report no note names; for those, build the map by hand with add-map:

python3 reaperd.py add-map MyKontactKit --roles '{"KICK_R":36,"SNARE":38,"HH_OPEN_1":46,"CRASH_R":49,"CHINA_R":52}'

For agents

Read AGENTS.md for the workflow, CLAUDE.md for the fast operational protocol, and bridge/command_schema.md for every command. Working JSON examples are in commands/examples/.

Develop

The CI matrix covers Windows, macOS, and Linux. From the repository root:

python -m pip install pytest
python -m pytest tests skills/drum-apparatus/tests -q
python -m py_compile reaperd.py reaper_mcp.py setup/install.py
lua bridge/test_bridge.lua
lua bridge/test_json.lua

The Lua checks require Lua 5.4. Live REAPER integration remains a separate manual gate because CI does not launch the DAW.

Layout

bridge/reaper_agent_bridge.lua   the bridge (runs inside REAPER, OS-neutral)
bridge/bridge_config.json        machine-specific config (regenerated)
bridge/command_schema.md         full command reference
reaperd.py                       cross-platform agent CLI (Python 3)
reaper_mcp.py                    MCP stdio server over the same bridge
setup/install.py                 wire auto-start into REAPER (cross-platform)
commands/examples/               one JSON example per command
skills/drum-apparatus/           DSL drum engine + kit-map auto-discovery
inbox/ outbox/ processing/ ...   runtime folders

Security

The bridge is a local file control channel: any process that can write to inbox/ can drive REAPER (load FX, change tracks, render). That's fine for a single-user dev box, which is what it's built for. Two rules keep it that way:

  • Keep the bridge folder local. Don't put it on a network share, a synced drive, or anywhere another machine/user can write. That's the real boundary.
  • Mutating commands run inside REAPER undo blocks, so anything an agent does is Cmd/Ctrl+Z-reversible.

Optional shared-secret token. On a shared or less-trusted box you can require a token: set auth_token to any string in bridge/bridge_config.json. The bridge then rejects any command without a matching token (AUTH_FAILED), and reaperd.py reads the same config and attaches it automatically — no other setup. Honest limit: the token lives in a local-readable config, so it stops accidental or other-app writes, not a local attacker who can read that file. Keeping the folder local is still the actual protection.

License

MIT. See LICENSE.

About

macOS port of the REAPER Agent Bridge — control REAPER from an AI agent over a local file bridge

Resources

License

Stars

4 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors