Skip to content

Architecture

systemBlue edited this page Jun 11, 2026 · 1 revision

Architecture

DeadCat is one Swift package plus one app project, organized so every piece reuses the same tested core. This page maps the modules, the boundaries between them, and the paths a request travels.

The modules

Module Kind What it does
DeadCatKit library The dependency-free core: an OSC 1.0 encoder and decoder, tested byte-for-byte against the specification, plus shared constants. Every server is built on it.
DeadCatReaperCore library The REAPER layer: tool declarations with annotations, JSON-RPC stdio handling, command-to-OSC routing, write verification against REAPER's feedback, the session cache, the media bridge, and the command-line parser.
deadcat-reaper executable The MCP server. Speaks initialize, tools/list, and tools/call over stdio and sends OSC datagrams to a local REAPER.
deadcat executable The terminal command. The same tool surface as one-shot commands, through the same validation and OSC path as the server.
apps/DeadCat app project The DAW for iPhone, iPad, and Mac, early in its milestone path. See The DAW and MVVM in the app.

The control path

A tool call arrives as JSON-RPC over stdio. The server validates every argument before anything touches the DAW: track numbers must be one-based integers, volumes normalized between 0.0 and 1.0, tempos between 1 and 960 BPM. A bad argument is rejected with a message naming the argument and the expectation, and nothing is sent. Valid calls go to REAPER as OSC over UDP on port 8000.

The feedback path

REAPER sends its state as OSC messages to a port the server listens on (9001 by default). The server keeps the latest value at every address in a session cache. Read tools answer from that cache after asking REAPER to refresh its control surfaces, so the answer reflects the session as it stands. Write tools use the same path in reverse: after sending a change, the server refreshes, waits for the feedback burst to settle, and reports the confirmed value. A value the cache held before the write never counts as proof.

The full round trip for one confirmed write:

  1. The client calls a write tool and the server validates every argument.
  2. The server sends the change to REAPER as an OSC datagram.
  3. The server asks REAPER to refresh its control surfaces and waits for the feedback burst to settle.
  4. The server reports the value REAPER confirmed, or says plainly that feedback has not confirmed it.

The media bridge

OSC has no media-item commands, so reaper_insert_media rides a small ReaScript. The server writes one request line to a file, triggers the registered script over OSC, and reads the script's answer back. The answer reports the track's item count after the insert, so the result is REAPER's account of what happened.

Boundaries

  • DeadCatKit stays dependency-free. The OSC layer knows nothing about MCP, REAPER, or any client.
  • MCPToolHandling is the seam between transport and DAW. The stdio server can be replaced (by the official MCP Swift SDK, for example) without touching the routing, and the router can gain a new DAW without touching the transport.
  • The CLI and the server share one parser and one router, so the two surfaces cannot drift.
  • The DAW app is separate from the OSC path. It plays and records audio directly through Apple's frameworks; it does not send OSC to itself. Where the app and the servers meet is an open design question tracked in the issues.

Adding a DAW

The roadmap adds DAWs one at a time, easiest control surface first: REAPER (shipped), then Ableton Live, Pro Tools, and Logic Pro. Each new DAW is a new routing layer over DeadCatKit; the tool grammar stays consistent so an assistant that knows one DeadCat server knows them all.

Clone this wiki locally