Draft. Written against the spec, ahead of the code. The words are the intent; the software is not there yet.
Getting started
Install it, let macOS ask its questions, find the token, and record one take two ways — from the popover and from a shell.
Rheocles is a menu bar app that bundles a headless daemon, rheocles-core. The
app is a thin client of the daemon over the same API you get. Launch the app
and the daemon comes up on localhost:7447; quit the app and it stays until
nothing is talking to it.
Install
brew install --cask artisan-build/tap/rheoclesOr the disk image from the releases page. The app, every nested binary and the disk image are Developer ID signed, notarized and stapled; Gatekeeper opens it without a right-click.
Requirements. Apple Silicon, macOS 15 Sequoia or later. The floor is
Sequoia because that is where SCRecordingOutput and process-level Core
Audio taps became dependable, and Rheocles uses both.
Permissions
macOS asks for each device class the first time it is needed, and Rheocles does not ask ahead of that — with one exception it cannot avoid.
| macOS asks for | when | where it lives afterwards | |
|---|---|---|---|
| a camera | Camera | the first arm | System Settings → Privacy & Security → Camera |
| a microphone | Microphone | the first arm | … → Microphone |
| system audio | System Audio Recording | the first arm | … → Screen & System Audio Recording |
| displays and windows | Screen Recording | the first GET /streams — opening the popover |
… → Screen & System Audio Recording |
The exception is Screen Recording: without it there are no displays to list, so nothing could ever be armed to trigger the prompt. The first stream list raises it once, and the grant takes effect on the daemon’s next launch — quit the app and open it again, and the displays are there.
The token
Every request needs a bearer token, on every transport. You do not have to go and get it. It is written to
~/Library/Application Support/Rheocles/tokenwith mode 0600, so any app running as you can read it and is paired with
zero clicks. That is how Pteroprompter and the NativePHP app pair. Anything
that cannot read a file gets the same token as a pairing code in the popover’s
settings, where it can also be rotated — rotation invalidates the old one for
everyone.
TOKEN="$(cat ~/Library/Application\ Support/Rheocles/token)"curl -s -H "Authorization: Bearer $TOKEN" localhost:7447/{ "name": "Rheocles", "version": "0.1.0", "hostname": "studio.local", "machineId": "…", "outputRoot": "/Users/len/Movies/Rheocles", "freeBytes": 812345678912, "auth": "bearer", "ports": { "http": 7447, "ws": 7448 } }Everything Rheocles ever tells you about a file is a path relative to
outputRoot. Store the relative path; join it to the root only if you need
an absolute one.
The first take, from the popover
- Click the mark in the menu bar. Every stream on the machine is listed — cameras, microphones, displays, system audio. Windows are hidden until Show windows is on in settings.
- Toggle arm on the ones you want. The row changes to ochre and the menu bar mark draws in outline: the device is live and costing CPU.
- Press Record. Every armed stream starts writing. The mark fills, the elapsed clock runs.
- Press Stop. The take folder under the output root has one file per
stream and a
manifest.jsonthat describes them.
The first take, from a shell
The popover’s Record button is the one-click form, POST /record. The
two-step form is what a client uses when it needs to know where the files will
be before frame one:
H="Authorization: Bearer $(cat ~/Library/Application\ Support/Rheocles/token)"B=localhost:7447
curl -s -H "$H" $B/streams # ids and armed statecurl -s -H "$H" -X POST $B/streams/camera:0x2300000fd9009c/arm -d '{"armed":true}'
curl -s -H "$H" -X POST $B/takes -d '{"name":"Episode 12"}' # → the manifest: id, paths; not recordingT=$B/takes/20260912T040433-fd9qcurl -s -H "$H" -X POST $T/start # the cuecurl -s -H "$H" -X POST $T/stopcurl -s -H "$H" $T # the manifest