Skip to content

roon-internal-api

Roon ships a small, sandboxed extension API. Its own desktop app speaks a much richer private protocol to the Core. This is a tinkering investigation into that protocol — how far can you drive a Core from a script? It's a proof-of-concept put together for fun, not a finished or supported tool.

Roon users have been asking for a more capable API for years. The official node-roon-api is deliberately limited — no metadata editing, no real library management, just a sandboxed slice of what the app can do.

So this is the brute-force route: watch what the desktop client itself sends to the Core, figure out the wire format, and see how much of it you can replay from your own code. It’s an experiment, not a product, and definitely not blessed by Roon.

This is one person tinkering against a single Core, confirmed by hand — not a test matrix across setups. Treat everything as “worked for me,” not “guaranteed.”

Protocol

Framing, varints, primitives, method calls, by-val structs, and the object graph are mapped well enough to talk to a Core. Cross-checked against my own packet captures.

A TypeScript port

~14k LOC. Typed wrappers are code-generated for all ~1550 methods, but the vast majority are untested — generated from metadata, not exercised live.

Tried by hand

Reading the object graph, favoriting, playing an album, pause, standby, and a reversible metadata edit each worked once or twice against my setup.

Lots still open

Most notably full streaming-catalog search (arbitrary Tidal/Qobuz terms). In-library search half-works. Plenty of rough edges. Pitch in →

Most of this — the protocol decoding, the TypeScript port, the codegen, and these docs — was done by pair-programming with Claude (Anthropic’s Claude Code). It’s as much an experiment in “how far can an AGI agent push a gnarly reverse-engineering task” as it is a Roon experiment.