Getting connected
When you first open Baton, it asks you to connect to your music server. You need three things:
- The server's address: the full address you open it at, such as
https://music.example.com. - How you sign in: a username and password, or an API key if your server offers one (recent versions of Navidrome do).
- Your username and password, or the API key.
Then click Connect. Baton checks the connection before it saves anything. If it works, your library loads. If not, it tells you why, so you can fix the address or the sign-in.
With a password, Baton never sends the password itself. It sends a code made from it with a fresh random value each time, which is how Subsonic servers expect to be asked. Your password or key is kept in the Keychain, the system's own password store, never in a plain file.
No server yet? On the Mac, Try the demo server fills in Navidrome's public demo. The iPhone also has a small demo library built in (see Baton on iPhone).
More than one music server. On the Mac, open Settings → Music Servers (⌘, opens Settings) and click Add Music Server…. Each server's ⋯ menu has Make Active, Check Connection, Edit… and Remove…. Baton keeps each server's sign-in separately and reloads the library when you switch.
See also: The two servers Baton uses and Backing up and restoring your settings.
The two servers Baton uses
Baton can talk to two servers of your own. They do different jobs, so the apps give them different names: your music server and your Baton server.
Your music server is where your library lives: Navidrome, or another Subsonic server, and the one you sign in to. It keeps your songs and albums, your playlists, what you have liked and rated, your play counts and the internet radio stations you save there.
Your Baton server is a small, optional Baton program you run yourself on a machine that stays on. It makes audiobooks from documents and offers the voices they can be read in. It keeps your place in a book and your shared settings in step between the Mac and the iPhone, and holds files for your other device for a while. It reads the short “Previously” recap of a book aloud on the iPhone, and it can answer the music friend.
One machine or two. In a typical home setup both run on the same always-on computer, and that is fine. They can just as well be two machines. Baton only needs the address of each.
What needs which. Playing, searching, downloading, liking and playlists need only the music server. These need the Baton server: making a book on the iPhone, or on the Baton server from the Mac; picking a book up on your other device; shared settings; sending files between devices; and the iPhone’s recaps. A book made on the Mac itself needs neither.
When one does not answer. Without the music server, Baton cannot play your library, though downloads still play. Without the Baton server, music carries on as normal. A book meant for it is made on the Mac instead, the iPhone suggests AirDropping the document to your Mac, and your place and settings catch up the next time it answers.
Where to set them up. On the Mac, the music server is under Settings → Music Servers, and the Baton server under Settings → Remote → Baton server, with the Baton server address and Baton server token. On the iPhone, open Settings with the gear at the top of Home. The music server is the Music server section at the top. The Baton server is under Settings → Music Friend: set Answers come from to Baton server to show its address and Baton server token.
The address is just the host and port, such as http://192.0.2.10:8788. The token is the long password you chose when you set the server up.
Baton on iPhone
There is an iPhone app. It plays the same library from the same server, and most of this page applies to it as written. The differences are the ones the phone brings. Settings opens from the gear button at the top of Home rather than from a menu, there is no menu-bar controller, and there is no mini-player window.
The tabs are Home, Albums, Library and Search, plus Friend once the music friend has passed its connection test (see The music friend).
It is on the App Store as Baton: Navidrome Music Player and needs iOS 18 or later. Unlike the Mac app it is a paid download, which is what covers the Apple developer account the Mac build is signed and notarized with. Its source is in the repository under the same licence, so you can build and install it yourself instead.
Setting it up from your Mac
Typing a server address and a long password on a phone keyboard is the worst part of setting up any music app, so you don't have to. The first-run screen offers three ways in. Later, Settings → Music server → Set up from a Mac… offers the first two.
- Scan a code from your Mac. On the Mac, open Settings → Remote → Link a device → Show pairing code, point the phone's camera at it, and allow it on the Mac. Your server address, your sign-in and your settings come across encrypted, with nothing to type and no passphrase. Both devices have to be on the same network, because the code carries a local address the phone connects back to.
- Choose an exported file. On the Mac, use Settings → About → Back up & restore → Export… and get the file to your phone however you like. This is the way that works when the two devices are on different networks. A file exported with your accounts is encrypted, so you'll need the passphrase you chose (see Backing up and restoring your settings).
- Type it in. The first-run screen takes a server address, a username and a password, the same as the Mac's.
Your likes, ratings, playlists and play counts need none of this. They live on your music server, and both apps read and write them as the same user, so they already match on every device. What travels in a pairing is the rest: your equalizer curve, crossfade, radio bans, and your server passwords and service tokens, which is why the transfer is encrypted. Pairing is a one-time transfer, but you can also turn on settings sync afterwards so a change on one device reaches the other.
Where this page says right-click
On the Mac, a right-click opens the menu of things you can do to a song, an album, an artist, a playlist or a station. On the iPhone, touch and hold instead (a tap plays). The menu is the same one: Play Next, Add to Queue, Add to Playlist, Like, Rate, Download, Save to Later, Share…, Set Alarm…, Start Timer…, Start Radio, Go to Album, Go to Artist, and the radio bans.
Widgets, the Lock Screen, and Live Activities
- Home Screen. A Now Playing widget in three sizes. The medium and large ones have Play/Pause and Next buttons. Touch and hold the Home Screen, tap +, and search for Baton.
- Lock Screen and StandBy. The same widget in the rectangular, circular and inline shapes. For a music player this is the one that matters most, because it's what you look at without unlocking anything.
- A Live Activity while music plays. A compact now-playing line on the Lock Screen, with a progress bar that runs on its own. On an iPhone with the Dynamic Island, expand it for Previous, Play/Pause, Next and Like.
Tapping a widget opens the full player. Tip: the link baton://player opens the full player directly, in either app.
The widget draws artwork already on the phone rather than fetching it. A widget's network access is limited, so a cover fetched on demand would never appear.
Siri and Shortcuts
Say “Play something in Baton” or “Play music in Baton” and Siri asks what you'd like, then searches your library and plays the results. “Resume Baton” picks up where you left off. In the Shortcuts app you'll find Play music, Pause music, Play or pause, Next track, Previous track, Like the current track, and Play songs matching, ready to drop into an automation. They use the same commands as the app's own buttons.
How much data it uses
Settings → Sound has a quality setting for each kind of connection: Wi-Fi Quality and Cellular Quality. Each takes Original, High (320 kbps), Medium (192 kbps) or Low (128 kbps). Wi-Fi starts on Original, which means no cap, and cellular starts on High. Cellular here also covers a personal hotspot and Low Data Mode.
Anything you've downloaded ignores both settings. It is already on the phone, at the quality it arrived in.
Browsing your library
On the Mac, the sidebar is your way into the library. On the iPhone, the same places are the tabs and the rows of the Library tab.
- Home: a greeting for the time of day and shelves you tap to play. On the Mac they include Recently Played, “Because You Liked…” radio, Recently Added, Rediscover and Your Mixes. The iPhone's Home has Recently Played, Your Mixes, Recently Added, Daily Mixes, From Your Music Server and Rediscover.
- Search: songs, albums and artists at once.
- Mixes: mixes Baton builds from how you listen (more below).
- Albums: sorted by newest, recently added, most played, name, artist, track count, length, rating, or at random, as a grid or a list.
- Artists: with biographies and artist pages.
- Playlists: the playlists on your server. Create, rename, reorder and delete them, and add or remove tracks. Changes are saved back to the server.
- Liked: everything you've hearted, split into Songs, Albums and Artists.
- Later: songs you've saved to come back to.
- Clippings and Books: readings you kept, and documents Baton turned into audiobooks (see Listening to a document).
- History: your play log (more below).
- Podcasts: the shows your server hosts, plus any you follow by their feed. Episodes stream and queue like tracks.
- Radio: your server's internet radio stations. Add, edit or remove a station with its name and stream address.
- Downloads: everything saved for offline play (see Downloads & offline).
- Folders: your music as it sits in folders on the server's disk.
On the Mac, right-click a sidebar section to hide it, and choose Show All Sections to bring them back. The Go menu always lists every section.
Rating and liking. Click the heart, or give 1 to 5 stars. Ratings are stored on your server under your user, so they follow you to any Subsonic app.
Selecting several. On the Mac, Shift-click a range, or press ⌘A to select everything. Then act on them together: like them, add them to the queue, save them as a playlist, download them, or mark them for removal.
Mixes
Baton builds six standing mixes from how you listen: Most Played, Fresh Additions, Top Rated, On Repeat, Forgotten Favorites (liked, but not heard in the last month) and Discover. Below them is a Genres section with a card for each genre you listen to. Each mix has its own page where you can Play, Shuffle, Queue, or download the whole thing. An agent can also build a mix to a length you ask for with music_build_mix.
History
History is a play log Baton keeps on each device: Recent, Tracks, Albums and Artists, over This Week, This Month or All Time. It counts a listen only once you've played about half the track, so skips don't clutter it. It's a free, private alternative to Last.fm or ListenBrainz. On the Mac you can export it as ListenBrainz JSON or CSV, import listens, or clear it.
On the iPhone, Recent reads from your server by default, so it includes what you played on the Mac. Switch to This iPhone for the phone's own log.
Playing music
The now-playing bar
On the Mac, a bar along the bottom of the window holds the scrubber, the playback controls, volume, the queue, the sleep timer's moon, the alarm clock and the AirPlay picker. Collapse it to a slim strip with ⌃⌘J, and expand it the same way.
On the iPhone, a mini player sits above the tabs with the cover, the title, Play/Pause, Next, and a ✕ that stops and closes the player. Tap it for the full player.
Full-screen Now Playing
Full-screen Now Playing has big artwork, a backdrop tinted from the album art, a waveform scrubber for downloaded tracks, and side panels for the Queue, Lyrics (synced line by line when your server has them) and Related tracks. On the Mac, Space plays and pauses, Esc exits, the left and right arrow keys skip ten seconds, and [ and ] switch the side panel.
On the iPhone, the full player's row of buttons holds Up Next, Lyrics, Transcript (Read Along for a book), Related, speed, the alarm clock, the sleep timer and AirPlay.
Tip: the link baton://player opens this screen directly, in either app.
Lyrics your server doesn't have. Turn on Settings → About → Lyrics → Look up missing lyrics on the Mac, or Settings → Sound → Look Up Missing Lyrics on the iPhone. Baton then asks LRCLIB, a free lyrics service, sending only the song's title, artist, album and length. It's off until you turn it on.
The floating mini-player
On the Mac, ⌥⌘M swaps the main window for a small card that stays on top of other windows, with the current track, artwork, scrubber, rating and Up Next. Keep it in a corner while you work. On macOS 26 and later it uses Liquid Glass.
The menu-bar controller
On the Mac, Baton also lives in the menu bar. Its menu shows what's playing (click the title for the full player) with Play/Pause, Next, Previous, Mute, Like, Volume, the Sleep Timer, Set Alarm… and Start Timer…. Below those are Open Baton, Mini Player, Recent Summaries…, Copy MCP Endpoint, Settings…, Check for Updates…, What's New…, About Baton and Quit Baton.
It keeps Baton, and the control server agents use, running in the background with every window closed.
Queue & modes
Drag to reorder, remove tracks, or clear the queue. Baton remembers the queue between launches and brings it back paused.
The Play button on an album, playlist, artist, mix, folder or podcast says Pause while that collection is playing and Resume while it is paused, so one button stops and starts it. Shuffle keeps the current track playing and puts the order back when you turn it off, including songs you added while shuffling. The Shuffle button beside a collection’s Play lights up only while that collection is shuffling. Repeat is Off, All or One. Continuous radio tops up the queue with similar tracks as you near the end.
Sleep timer
The sleep timer stops the music for you. Tap the moon icon: in the player bar or the full-screen player on the Mac, or in the full player on the iPhone. On the Mac it is also in Playback → Sleep Timer and in the menu-bar menu (hidden there while radio plays). On the iPhone the same moon sits at the top of Clippings, Books and Read Along.
Choose 15, 30 or 45 minutes, or 1, 2 or 3 hours. Or choose End of track to stop when the current song finishes (End of chapter for a book, End of episode for a podcast). When a timed stop comes, Baton fades out over five seconds and then pauses, rather than cutting off mid-note.
To cancel, choose Turn off sleep timer on the Mac (Turn Off Sleep Timer in the menus) or Cancel sleep timer on the iPhone. An agent on the Mac can set a timer in minutes with music_sleep_timer.
See also: Alarm and Timer, which starts music rather than stopping it.
Transcripts and summaries
Baton can write down what's said in a podcast episode or any other spoken track, using a Whisper speech-to-text server you run yourself. Turn on Transcribe spoken tracks and enter the Whisper host: under Settings → Speech → Transcription on the Mac, or Settings → Transcription on the iPhone.
Then open the Transcript panel in the full player. The current line follows the audio, and tapping a line jumps there. Summarize this episode, at the top of the panel, asks a model for a short overview and chapter marks you can tap. Baton uses only a model on your own network for this, and refuses a hosted one, because a transcript is everything that was said.
Baton never transcribes on its own: it waits for you to ask. The audio goes to the Whisper server you named, and nowhere else.
Alarm and Timer
These work like the Alarm and Timer in Apple’s Clock app, except that what rings is yours: a song, an album, a playlist, a book from where you left it, or a radio station. The sleep timer stops music; these start it. Both apps have them.
Setting an alarm or a timer
Tap the clock beside the sleep timer’s moon. On the Mac it is in the player bar and the full-screen player, and opens a popover. On the iPhone it is in the full player, and opens a sheet.
You can also choose Set Alarm… or Start Timer… in the menu of a song, an album, a playlist or a book, with that item already chosen. On the Mac they are in the Playback menu and the menu-bar menu too, and open a window called Alarm. On the iPhone they are also in the sleep timer’s menu.
The Timer tab has 5 min, 10 min, 15 min, 30 min, 1 hr and Custom (any length up to 23 hours, 59 minutes and 59 seconds), then Start. One timer runs at a time, with Pause, Resume and Cancel.
The Alarm tab has a time, and quick picks: 7:00 or 8:00 (each says today or tomorrow, whichever comes next, in your clock’s format), In 1 hour and In 8 hours. Then come Repeat days, a Label, Snooze (on to begin with), Gentle Wake (off to begin with) and Then play. Save it with Save on the iPhone or Save Alarm on the Mac.
Your alarms are listed under Your Alarms, each with its own switch. A one-off alarm switches itself off after it goes off.
An alarm and a timer together
A timer and an alarm can be set at the same time. While a timer runs, a small pill above the player counts it down: “Timer 12:34 · then …”. An alarm due within a day gets a pill showing its time: “Alarm 7:00 · then …”.
With both set there are two pills. On the iPhone the timer’s sits above the alarm’s; on the Mac they sit side by side beside the clock. Each pill’s ✕ affects only that one: it cancels the timer, or switches the alarm off. Tap a pill to change things.
Gentle Wake
Gentle Wake is for an alarm that shouldn’t jump at you. It’s off until you turn it on, and each alarm keeps its own setting. Timers don’t have it, because a timer is for something you need to hear straight away.
When the alarm goes off, Baton starts quiet and raises the music to your volume over the first 30 seconds, never louder than you set it. That works for songs, books and radio stations. The rise waits until the music is actually playing.
- Change Baton’s volume yourself, or mute, and the rise stops at your setting.
- Pause, Stop and Snooze keep the level the rise had reached, so nothing blasts out. The next time music plays, it plays at your volume.
- On the iPhone, the alarm sound rises too: up to full over its first 20 seconds. From iOS 26.1 the system repeats the alarm sound until you answer it, and each time round it starts quiet and climbs back to full.
- On the Mac, a notification for a Gentle Wake alarm uses a rising chime.
Choosing what plays
Then play is what starts when it goes off. It begins as the item whose menu you used, or what’s playing, or the last thing you played. Tap it to open What to Play: search your songs, albums, playlists, books and radio, browse them, or pick from Recently Played.
Recently Played is the last 50 songs played on this device, newest first and each listed once. It comes from this device’s own play log, so it holds only songs you listened to properly, and it is empty if you have turned the log off or cleared it. The round button on a row plays ten seconds first. Nothing has to be playing to choose.
When it goes off
This is what happens while Baton is running, whether it’s open or playing in the background. Your choice starts at the time, and a ringing screen comes up over whatever you’re doing, with three answers:
- Keep playing, open player takes you to the full player.
- Snooze 9 min pauses and goes off again in nine minutes. An alarm offers it only when its Snooze is on. For a timer it starts a fresh nine-minute timer.
- Stop pauses the music.
If the music hasn’t started ten seconds after the time, Baton’s chime plays instead. An alarm more than ten minutes late (because the Mac was asleep, say) starts nothing, and Baton tells you it was missed.
When Baton is closed on the iPhone
On iOS 26 and later the alarm rings as a real system alarm on the Lock Screen, after asking your permission the first time. It rings with your song: when you save an alarm or start a timer, Baton keeps the first 29 seconds of the track you chose as its sound. If Baton can’t get the song (offline, say), it rings Baton’s chime, and failing both, the iPhone’s own alarm sound. A radio station always rings the chime.
Tap Play, or open Baton within ten minutes, and the whole track plays from the start. With the alarm’s Snooze on, the alert’s button is Snooze instead; open Baton while it rings or snoozes and your track plays.
On iOS 18 to 25 it arrives as a notification that plays the same 29 seconds once, or the chime, with Play and, when Snooze is on, Snooze.
Settings → Alarm and Timer → Rings with Baton closed shows whether alarms may ring with Baton closed, with Allow Alarms or Turn On in iPhone Settings to change it.
When Baton is closed on the Mac
Baton usually keeps running in the menu bar, so it plays the whole track itself at the time. If Baton isn’t running, a notification with Baton’s chime appears instead, and clicking it opens Baton and plays your choice. That needs notifications allowed for Baton; if they are off, the alarm sheet says the alarm works only while Baton is running.
Alarms follow the clock on the wall: 7:00 stays 7:00 when the clocks change or you travel. They belong to the device you set them on, and aren’t shared between your iPhone and Mac.
The music friend
Baton has a music friend: ask for something in plain language and it works out what you meant, then does it with your library and your player. "Something calmer", "what is this?", "play the live version instead". It can do what the buttons can.
On the Mac, open it with Go → Music Friend (⇧⌘F). On the iPhone it is the Friend tab, which appears once a connection test has passed. Setting up a provider is not enough on its own: a key with a typo in it is still a key, so Baton waits until one real request has worked before it shows you a tab that promises to answer.
One friend everywhere. The window on the Mac, the tab on the phone and the Telegram and Discord bridges all run the same conversation. What it has learned about you in one place it knows in the others, and a thumbs-down you give here counts the same as one you give in Telegram.
Plain commands stay plain. "Pause", "next", "louder" and the like are understood directly and answer at once, without asking a model anything. That keeps the obvious things instant and free; the model is for the requests that need thinking about.
Turning it on, on the Mac
The setting lives in Settings → Remote, which is also where the Telegram and Discord bridges are. That pane covers everything that answers you in words, so the friend's model is set up there too, in the Natural language section near the bottom.
- Open Settings → Remote and scroll past Telegram, Discord, Linking, Devices and Baton server to Natural language.
- Turn on Understand plain English. Leave Enable remote control at the top of the pane alone unless you want Telegram or Discord as well; the friend window does not need it.
- Pick a Provider: Anthropic or OpenAI-compatible. Choosing one fills in a matching model and base URL, so the only thing left is the key.
- Paste your API key and click Save beside the field. It saves on the button, not as you type, and it goes to your login Keychain rather than a preferences file.
- If you like, change Model or API base URL. This is where a model on your own machine goes: point the base URL at it and nothing leaves the house.
- Click Test. It sends one real request the way a message would, so a pass means the next thing you say will work.
- Turn on Let it look around first. Without it, one message becomes one command decided blind: ask for "lazy music" and you get "nothing matched" even with a shelf of things tagged chill. Remember what you tell it sits underneath and needs it on.
Then choose Go → Music Friend, or press ⇧⌘F. If the window still says it has nothing to answer with, step 2 is the one that was missed: a key with the switch off does nothing.
Turning it on, on the iPhone
The same settings have a screen of their own: Settings → Music Friend. The Friend tab is not there until a connection test passes, so if you cannot find it, that is why.
Answers come from picks where the thinking happens, and the two choices want very different things.
Model provider talks to a model directly from the phone. Choose the provider, paste the key, name the model, and press Test connection. The test asks the model to handle a real request and checks it picked the right command, so a pass means the next thing you say will work. When it passes, the Friend tab appears.
Baton server sends the question to your Baton server at home, so your key stays there instead of on your phone. This is the one people get wrong. A Baton server is baton-gateway, the small program that also keeps your settings in step between devices. It is not a model endpoint. Pointing Baton server at Ollama, vLLM, LiteLLM or anything else that speaks an LLM API will not work, because Baton asks it for /v1/agent and only a Baton server answers there. To use a model on your own machine, choose Model provider, or set BATON_LLM_BASE_URL on the Baton server itself.
The two addresses on this screen also want opposite shapes, which is easy to miss because they sit one above the other:
| Field | Address |
|---|---|
| Baton server | The bare host and port, http://192.0.2.10:8788. The Baton server listens on 8788 by default. A trailing /v1 is dropped if you paste one. |
| Model provider | The API root including /v1, because that is where /chat/completions hangs off. |
About the fallback. If the Baton server cannot be reached, Baton falls back to the model provider, so a Baton server that is asleep or has moved will not take the friend down with it. The fallback does not make the Friend tab appear, though, because that test checks the route you actually chose. If you picked Baton server and have none running, test as Model provider instead.
Talking, and telling it when it is wrong
On the Mac, the composer has a microphone: click it and speak, then click it again to stop and send what you said. The first time, the system asks for permission to use the microphone and to recognise speech. If you say no, the window tells you so instead of appearing to listen. Typing is always there as well: Return sends, and Option-Return starts a new line.
Every answer has a thumbs-up and a thumbs-down under it. A thumbs-down asks what went wrong (wrong track, misunderstood, too slow, too chatty), and that correction goes into what it reads before answering next time.
The Friend Log shows what it remembers and what it has learned, and lets you make it forget either. On the Mac it is Settings → Friend Log. On the iPhone, tap the Friend log button at the top of the Friend tab.
Gapless, crossfade & sound quality
- True gapless playback. Live albums and continuous mixes play with no silence between tracks. Baton loads the next track ahead of time and saves a streamed one to disk first. On the Mac you can limit that to Wi-Fi, so it doesn't eat into a metered connection.
- Crossfade. Overlap the end of one track with the start of the next. Crossfade and gapless can't both be on: one overlaps the tracks, the other butts them together.
- Loudness normalization (ReplayGain or R128). Even out the volume across tracks or albums using your server's ReplayGain data, with an adjustable pre-amp on the Mac.
- Parametric equalizer. On the Mac, open Audio → Equalizer… (⌥⌘E) or Settings → Equalizer; on the iPhone it is Settings → Equalizer. Ten bands, each with its own frequency, width and gain, a live response curve, and presets (Flat, Bass Boost, Treble Boost, Vocal, Rock, Electronic, Loudness, Vocal Boost, Bass Reduce). It is off to begin with, and when it's off the sound passes through untouched.
You don't have to set any of this up. After you've played about twenty tracks, Baton picks defaults from how you listen: gapless for album listeners, a gentle crossfade and autoplay for shuffle listeners. It tells you what it did, and you can change any of it in Settings.
Downloads & offline
Baton can download tracks, albums, mixes or playlists and play them from the device. You get full quality without streaming again, and your favourites stay close. A downloaded track is always played in place of the stream.
On the Mac, Downloads in the sidebar lists everything you've saved, with the total size on disk, and Settings → Playback → Downloads has the folder and file-name format. On the iPhone, open Library → Downloads: swipe a download to remove it, and Retry all tries failed ones again.
Both have Offline mode, which keeps playback on downloaded files only.
See also: How much data it uses on the iPhone.
Listening to a document
Baton can turn a document into a narrated book that lives in Books: in the sidebar on the Mac, and in Library on the iPhone. It reads a PDF, an EPUB, a web page (saved as HTML, or just its link), a Markdown file or plain text.
On the Mac, choose File → Import Document… (⇧⌘O) or File → Import Link…, or drag the file onto Books. In Finder, Control-click the file and choose Open With → Baton or Services → Make an Audiobook with Baton; Baton never becomes the default app for these files.
On the iPhone, share the file or the web page to Baton from another app’s share sheet (Safari works too), open it in Baton from Files, or use the + menu on the Books screen: Import a File… or Import a Link…. However it arrives, the book lands in Books.
Before anything is made, Baton shows what it found: the title and author, the chapters, anything it set aside (a publication note on the title page, for example) and anything it could not read, along with roughly how long the book will be and how much space it will take. A scanned PDF, one made of pictures of pages, is read with text recognition, and Baton names the pages it read that way, because recognition can misread a word. Choose Make Audiobook to start.
The narrator. On the Mac, a language model suggests three voices for the book, with its reason, and you can hear each in the book’s own words before you choose. Baton asks a model on your own machines: Apple Intelligence on this Mac, a model you run with Ollama or LM Studio (set up under Settings → Speech → Models on this Mac), or the one your Baton server uses. A cloud model is asked only if you allow it (see Book text and cloud models). With no model answering, Baton starts on the default voice for the book’s language, and you can still choose another. On the iPhone, the import screen lists the same three voices the Mac offers without a model, from those your Baton server has (Heart first, or Emma for a book in British English), and you tap one to choose it and its play button to hear it.
Where it is made. The import sheet asks Made on: Baton server or This Mac, unless Make books on in Settings → Speech already says which. Your Baton server makes the book while the Mac sleeps, with its own voice server. This Mac narrates it with the engine chosen under Voice engine for books: its built-in voices, a voice server, or Automatic, which uses the built-in voices when they are downloaded and have the book’s voice (see Voices: on this Mac or on a server). Either way it is made one chapter at a time, starting with chapter 1, which is usually ready in a minute or two while the rest follows as you listen. The phone has no voice host of its own, so it always asks your Baton server, and says so when none is set up. Page numbers, running heads and words broken across lines are tidied up first, and anything that looks like a password or key is left out.
When your Baton server cannot make books, the iPhone offers Send to my Mac in place of Make Audiobook. Your Baton server holds the document until your Mac collects it, which Baton on the Mac does while it is open with Documents on. There the document opens in the import sheet, marked with the device that sent it. Not Now keeps it waiting in a list at the top of Books; Make Audiobook or Discard takes it off the Baton server. With no Baton server at all, the phone suggests AirDropping the file or link to your Mac instead.
If the voice host stops answering, the book pauses and its row says why. It carries on by itself when the host is back. It never finishes in a different voice. Quitting is fine too: if you quit Baton while a book is being made, it picks up where it stopped the next time Baton opens, and nothing already narrated is made again.
Listening. A book is one row in Books, with its author, its length and how much of it you have heard. Open the row to see its chapters. Play starts where you left off, and the chapters play in order like the tracks of an album. That holds on the iPhone too: Play picks up at the chapter and the moment you last heard on either device, and finishing a book on the iPhone marks it finished on your other devices as well. A book made on the Baton server arrives on every device that collects clippings, chapter by chapter. Once you finish it, its row on the Mac says how long the Baton server keeps it (“Kept until 2 November”).
Coming back after a break. On the Mac, press Play on a book you last heard more than a day ago, once you have heard a fair part of it, and Baton offers Hear Recap: a short spoken summary of what you have heard so far, never anything past where you are, and then the book carries on. Just Play skips it. The recap is written by a model, like the narrator suggestion.
Exporting. On the Mac, Control-click a book and choose Export Audiobook… to save it as one M4B file that Apple Books and other audiobook players open, with a chapter mark where each chapter starts. The book has to be finished being made first. For a book made on this Mac, the marks need ffmpeg (brew install ffmpeg); without it you get one file with no marks, and Baton says so.
Covers. A book shows its cover on its row, at the top of the open book and in Now Playing, including the lock screen and Control Center. An EPUB keeps its own cover when you import it. For any other book, open its menu (Control-click it on the Mac, or open it and choose More; on the iPhone, tap the cover or touch and hold the book’s row). Find Cover… looks the book up on Open Library and shows the covers it has; only the title and author are sent, and only when you ask. Make a Cover draws a simple cover from the title and author on your device, so it needs both. Choose Image… uses a picture you pick, and Remove Cover goes back to the plain book mark. The cover travels with the book through your Baton server, so a cover chosen on the Mac shows on the iPhone, and the other way round.
Names the narrator gets wrong. With a Kokoro narrator, the Mac’s import sheet lists names it might stumble on, each with a pronunciation a model proposed, and you can correct any of them or add your own. Later, Pronunciations… in the book’s menu opens the same list. Saving makes again only the chapters that say a word you changed.
Turning it off. Documents are on for everyone. The Documents switch under Settings → Speech on the Mac, or Settings → Documents on the iPhone, takes the import items, the drop target and the book rows away on that device alone, at once and without a relaunch; the other device keeps its own setting.
For agents. The import_document tool takes the path of a file on this Mac, or a link to one, and makes the book the same way, where Make books on says. With Ask each time it makes the book on this Mac unless the agent asks for the Baton server, and if the Baton server does not answer, this Mac makes it. Its reply says where the book is being made. document_context lets an agent read the passages of a book you have already heard, never anything past where you are, so it can answer a question like “who is Kuno again?” without spoiling the rest. These two, and every book tool, are listed only while Documents is on (see agent control).
There is no baton:// link that opens Books, Clippings or Read Along.
Voices: on this Mac or on a server
A book is read aloud by a voice engine. Baton can use one of two, and on the Mac you choose which under Settings → Speech → Voice engine for books:
- Built-in voices on this Mac. Kokoro’s English voices, run by Baton itself after a one-time download. Mac only.
- Voice server. A Kokoro or Chatterbox server you run, on this Mac or on another machine on your network, reached by its address.
| Built-in voices on this Mac | Voice server | |
|---|---|---|
| Where it runs | Inside Baton on this Mac | A Kokoro or Chatterbox server, on this Mac or another machine |
| Quality | Kokoro. In a side-by-side listening test it sounded the same as the server | Kokoro sounds the same; Chatterbox adds its own voices and voice cloning |
| Speed | About 13 times faster than real time on an M5 Max | About 17 times faster than real time for Kokoro on a home-network server |
| Languages and voices | English only, 28 voices | Every voice the server has: Kokoro’s other languages, and Chatterbox |
| Privacy | Nothing leaves this Mac | The book’s text goes to the server’s address |
| Network | None. Works offline | The server’s address has to answer while the book is made |
| What to set up | Download 342 MB once. Needs a Mac with Apple silicon | Run the server, and enter its address under Settings → Speech → Services |
The speeds were measured once, on one Mac running a test build of Baton and one Kokoro server on a home network, in October 2026. Your Mac and server will differ.
Choosing on the Mac. Settings → Speech → Voice engine for books has three choices. Each shows what it needs and how it stands right now: downloaded or not, or each server’s address and whether it answers.
- Automatic (the default). Whenever the built-in voices are downloaded, Baton uses them first for every voice they have (their 28 English voices), and the voice server for every other voice. Without the download, every voice goes to the voice server.
- Built-in voices on this Mac. Only the built-in voices. A voice they do not have, such as a Chatterbox voice or a Kokoro voice in another language, is not sent to a server: the book pauses and its row says why, and the import sheet offers only the built-in voices. The same happens if they are not downloaded yet.
- Voice server. Only your voice servers, even when the built-in voices are downloaded. If no server answers, the book pauses until one does.
A paused book carries on by itself once the reason is gone, for example after the download finishes or after you change the choice. The choice is this Mac’s alone: it does not travel to your other devices, and Reset to Defaults in the Speech pane puts it back to Automatic. Spoken summaries and Read aloud are not affected; they use the servers under Services.
Where a book is made. Under the same heading, Make books on decides where the Mac makes a new book: Ask each time (the default) shows the choice in the import sheet, starting on the Baton server when it answers; This Mac or Baton server makes it there without asking. If the Baton server is chosen and not answering, the sheet says so and the book is made on this Mac. The Baton server reads books with its own voice server, the one named in the Baton server’s own setup, not with this Mac’s Voice engine for books.
On the iPhone there is no choice to make. The phone has no voices of its own, so every book is made on your Baton server with its voice server. Settings → Documents says so. It needs the Baton server’s address and token under Settings → Music Friend, and the Baton server’s voice server answering. When the Baton server cannot make a book, Send to my Mac hands it to Baton on your Mac instead.
Setting up the built-in voices
- On a Mac with Apple silicon, open Settings → Speech. Make sure Documents is on.
- Under Voice engine for books, press Download (342 MB) below Built-in voices on this Mac. Nothing downloads until you press it, and Cancel stops it; a later Download picks up where it stopped.
- When the line under the choice says Downloaded, 28 English voices, choose Automatic or Built-in voices on this Mac.
Remove takes the download away again. An Intel Mac cannot run them, and the line says so.
Setting up a voice server
- Run Kokoro, Chatterbox or both on this Mac or on a machine on your network (see The voices under Spoken summaries).
- In Settings → Speech → Services, enter each address, such as
http://YOUR-TTS-HOST:8880for Kokoro, and press Test this connection. - Under Voice engine for books, the Voice server line shows each address and whether it answers. Choose Voice server, or leave Automatic.
Setting up the Baton server’s voice server
The Baton server makes books with the voice server named in its own setup, whichever device sent the book.
- Run Kokoro (and Chatterbox if you want its voices) where the Baton server can reach it. It can be the same machine or another one on your network.
- In the Baton server’s environment, set
BATON_TTS_KOKORO_URLto Kokoro’s address, for examplehttp://YOUR-TTS-HOST:8880, andBATON_TTS_CHATTERBOX_URLto Chatterbox’s if you use it. WithoutBATON_TTS_KOKORO_URLthe Baton server looks for Kokoro on its own machine athttp://127.0.0.1:8880. - Restart the Baton server. Its log names the voice servers it uses (
books: …, TTS …). The Baton server also needs ffmpeg to make books.
Voice the dialogue
Normally one narrator reads everything. Turn on Voice the dialogue when you import a book, on the Mac or the iPhone, to give each speaking character a voice of their own. It is off for the first book you import on a device. After that it starts the way you last left it there.
A model reads passages from across the book and proposes a cast: who speaks, the names the text calls them by, and a voice for each. Nothing is used until you check it. Check the Cast… lets you rename someone, merge two names for one person, mark the narrator, remove someone who never speaks, and choose a voice for each from every voice engine you have, with Hear to listen to them say one of their own lines. Then choose Use This Cast.
Baton then works out who says each line. A line with a speech tag (“said Mr. Bennet”) is placed by rules, and a model is asked about the rest, with a progress line and a Skip button. One line tells you how many have a speaker, and the narrator reads any that nobody can place. With no model answering, the sheet says so and the book stays with one narrator.
Book storage
A book takes about a third of a megabyte for each minute of listening: a 25 page story is about 25 MB. These are in a book’s menu in Books:
- Remove Download frees the space and keeps the book’s row, its words, its voice and your place. A single chapter can go the same way. It is only offered when the audio can come back.
- Download Again brings the chapters back from your Baton server. Render Again makes them again: on this Mac for a book made here, or on the Baton server once it has removed its copy.
- Keep on This Mac (or Keep on This iPhone) means no rule or suggestion ever removes it.
- Delete Book… asks which you mean. Remove from This Mac (or Remove from this iPhone) removes it from this device; Delete Everywhere also removes it from your Baton server and your other devices. A book removed from one device stays on your Baton server for your other devices.
A deleted book and a removed download stay in Recently Removed for a week. A deleted book’s audio is kept until then, so Restore brings it back as it was, and Delete Now frees the space sooner.
Storage is under Settings → Storage on the Mac and Settings → Documents → Storage on the iPhone. It lists this device’s books with their sizes, the Baton server’s books with how long it keeps finished ones, and three cleanup rules: After I finish a book, Books I haven’t played and Space for books. Nothing is removed until you choose a rule. A rule removes a download, never the book, and never the book you are listening to or one marked Keep. Each device has its own rules.
At most once a week, Books may suggest something: removing the download of a book you finished a while ago, or, when the device is short of space, of your largest finished books. Always Do This turns the first kind into a rule that removes a finished book’s download a week after you finish it.
Book text and cloud models
Models on this Mac, on your Baton server and Apple Intelligence keep a book on your own machines, so Baton uses them without asking. A cloud model, such as the one your music friend may run on, gets a book’s text only with your permission.
The first time only a cloud model could suggest a narrator, the import sheet asks whether to send it the book’s opening: Not Now, Allow Once or Always. To change your answers later, open Settings → Agents and find Book text and cloud models. Each cloud model you have set up has two switches:
- Short excerpts: the book’s opening for the narrator suggestion and the cast list, and the names a voice might stumble on.
- Chapters: the chapters you have already heard, for a recap, and the lines a model places for Voice the dialogue.
Forget My Answers clears them all. The answers stay on this Mac, and anything that looks like a password or key is taken out before any text is sent.
Clippings
Clippings sits next to Books and keeps the short readings you chose to keep. On the Mac, after Baton reads something aloud, choose File → Keep Reading in Clippings (see Reading what’s on your screen). A clipping plays through the ordinary player, and you can find one by searching for words said in it.
Right-click a clipping on the Mac for Play Next, Rename…, Change Voice… and Delete…, which asks whether to Remove from This Mac or Delete Everywhere. On the iPhone, Clippings is in Library; it collects new clippings when you open it or pull down to refresh.
Scrobbling
Scrobbling means reporting what you listen to. Baton reports your listens to your music server, which keeps its play counts up to date, and to ListenBrainz or Last.fm if you sign in to them: under Settings → Playback → Scrobbling on the Mac, or Settings → Scrobbling on the iPhone.
A track counts once you've played about half of it (at most a few minutes for a long track), the usual rule. Listens made offline wait in a queue and go when you're back online; Send now sends them straight away.
Media keys & AirPlay
- Media keys and Bluetooth remotes. On the Mac, the play, next and previous keys (F7, F8, F9) and the buttons on Bluetooth headphones and remotes all control Baton, and the current track shows in Now Playing in Control Center.
- AirPlay. To send the sound to an AirPlay speaker, use the AirPlay picker: in the now-playing bar on the Mac, and in the full player on the iPhone. Chromecast, Sonos and UPnP casting are planned.
Keyboard shortcuts
These are on the Mac. Each one is also an item in the menu named above its group, so you can find it there if you forget the keys.
Playback menu
| Action | Shortcut |
|---|---|
| Play or pause | ⌃⌘P |
| Next track | ⌃⌘→ |
| Previous track | ⌃⌘← |
| Skip back or forward ten seconds | ⌥⌘← / ⌥⌘→ |
| Volume up or down | ⌃⌘↑ / ⌃⌘↓ |
| Mute or unmute | ⌃⌘M |
| Like or unlike the current track | ⌃⌘L |
| Rate the current track 1 to 5 stars | ⌃⌘1 to ⌃⌘5 |
| Clear the rating | ⌃⌘0 |
| Show Queue | ⌘U |
| Get Info on the current track | ⌘I |
| Replay Last Summary | ⌃⌘R |
| Stop Speaking | ⌃⌘. |
| Minimize or expand the player bar | ⌃⌘J |
| Mini Player (closes the main window) | ⌥⌘M |
The Playback menu also holds Shuffle, Repeat, Speed, the Sleep Timer, Set Alarm…, Start Timer… and Share Current Track….
Go menu
| Action | Shortcut |
|---|---|
| Go to a sidebar section | ⌘1 to ⌘9 |
| Find… | ⌘F |
| Now Playing | ⌘0 |
| Refresh Library | ⌘R |
| Music Friend | ⇧⌘F |
| Hide or show the sidebar | ⌃⌘S |
Other menus
| Action | Shortcut |
|---|---|
| Baton → Settings… | ⌘, |
| File → Import Document… (while Documents is on) | ⇧⌘O |
| File → Save Reading as Audio… | ⇧⌘S |
| Audio → Equalizer… | ⌥⌘E |
| Help → Baton Help | ⌘? |
Outside the menus. Space plays and pauses in the main window. In the full-screen player, Space plays and pauses, Esc exits, the left and right arrow keys skip ten seconds, and [ and ] switch the side panel between Queue, Lyrics and Related. In an open book, ⌘[ goes back to Books. In lists, ⌘A selects everything.
Webhook actions
Webhook actions send a media item to an HTTP endpoint you choose. They're aimed at podcast episodes: for example, POST an episode's audio URL to a service that transcribes it. On the Mac, set them up in Settings → Actions with Add Action…: give an action a name, pick a method (POST, GET, PUT, PATCH, DELETE) and a URL, add any headers, and write a body for methods that send one.
Anywhere you write a URL, header, or body you can drop in tokens that Baton fills from the episode: {title}, {channelTitle}, {enclosureUrl}, {feedUrl}, {guid}, {pubDate}, {durationSec}, {episodeImageUrl}, {channelImageUrl}, and {description}. Your actions appear in an episode's ⋯ menu and right-click menu, and in the bar that appears when you select several. They only ever run when you choose them.
Spoken summaries: agents that talk
Baton's other agent-native feature is a voice. Through the speak_summary tool, an agent can have Baton say a short line out loud in a natural voice, so you hear “deploy finished, all green” instead of watching a screen for it. Baton can act on your music and it can talk back.
This is most useful with more than one agent running at once. Give each agent, or each kind of task, its own voice, and you can tell them apart by ear without switching windows: the deploy agent in one voice, the research agent in another, an alert in a third. Set it all up under Settings → Speech on the Mac.
How an agent talks
speak_summary takes the line to say (text, up to 2,000 characters), a category that picks the voice from your map, an optional voice or engine, and a mode: notify (a notification with a Play button, the default), banner (a banner inside Baton) or auto (speak it now).
You decide what is actually spoken. With the settings as they come, nothing is spoken until you press Play, and auto is treated the same way. An agent can speak straight away only once you turn on Allow the agent to play it immediately under Settings → Speech → Delivery. The same section sets When a summary arrives, and whether Baton alerts you with a notification (on to begin with), a banner inside Baton, or both. Your choices there win over the mode an agent asks for.
It also takes a session: a short name for the agent itself, usually the repo it is working in. Baton shows it above the transcript in the summary window, so you can see who is talking without it being read to you, and remembers it for the rest of that agent's connection. The name also picks the voice: you keep a list of agent-and-voice pairs in the Speech pane, and anything not on it speaks in a voice from outside the list, so a project you named never sounds like one you did not.
On a Bluetooth speaker, Baton holds a moment of silence before it speaks. A Bluetooth speaker powers its radio down when idle and takes a moment to wake, which otherwise swallows the first word or two. The wait applies only over Bluetooth, so wired and built-in output are never delayed, and you can lengthen it with Bluetooth head start under Settings → Speech → Delivery if your speaker is slower than most.
One voice per agent
The map from category to voice is what lets you tell several agents apart. Baton comes with a starter map you can edit, add to and preview:
| Category | Voice | Good for |
|---|---|---|
default | Kokoro af_heart | Anything with no category |
research | Kokoro af_bella | A research or analysis agent |
deploy | Kokoro am_michael | Deploys and builds |
ops | Kokoro am_fenrir | Ops and infrastructure |
alert | Kokoro af_nova | Anything urgent |
premium | Chatterbox Emily.wav | A cloned or premium voice |
es | Kokoro ef_dora | Spanish |
Add a category per agent, pick the engine and voice, and preview it. A five-agent run becomes five distinct voices, and you always know who's talking.
The voices
Baton speaks through self-hosted, OpenAI-compatible text-to-speech servers on your own network, so the audio never leaves your machines: Kokoro for fast preset voices (the default) and Chatterbox for premium voices and voice cloning. Enter each server's address under Settings → Speech → Services, and check it with the arrow button beside it (Test this connection).
speak_summary still works and a line is never silently dropped (the fallback is on by default).
Reading what's on your screen
The same voice will read you a document. Select an article in Chrome or a wall of build output in a terminal, choose Services → Speak with Baton or press the shortcut you set, and Baton reads it while your music ducks underneath and comes back at the level it was. A window shows the text with the sentence being spoken highlighted.
Nothing watches your screen. Baton has no idea what is on it until you select something and ask. Before it speaks a word, Baton removes anything shaped like a credential, strips terminal escape codes and shell prompts, and announces a block of code instead of pronouncing its punctuation.
A reading isn't kept unless you ask. File → Save Reading as Audio… writes it to a file you choose, and File → Keep Reading in Clippings keeps it in Baton (see Clippings). A reading you stop partway can be picked up again from File → Resume Reading, until you choose Forget Saved Readings there.
An agent can hand over a document too. The read_aloud tool takes text an agent already has and reads it, which is the practical answer for a web page: pulling the article out of a page, rather than the navigation and the cookie banner, is real work, and an agent driving the browser has already done it. Pass text, optionally source (the site or app it came from, which labels the reading and can pick its voice), kind (browser, terminal or generic), and gist: true to have a long article summarized and the summary read instead.
Let an agent control your music
This is the feature Baton is built around: it can be driven by software, not just by you clicking buttons. Baton hosts a small control server on your Mac that speaks MCP (the Model Context Protocol), the same protocol Claude and other AI agents use to talk to tools. So you can say things like:
- “Put on a 40-minute instrumental focus set.”
- “What's playing? Like it.”
- “Make a playlist of everything I liked this month.”
- “Turn it down” / “skip this” / “play some jazz.”
…and the agent carries them out in Baton, searching your library, building a queue, starting playback, rating tracks, and creating playlists. The control surface exposes the same operations Baton's own UI uses, so anything the agent does is something you could have done by hand. You don't need an agent to use Baton; this is an extra surface on top of a complete player.
Four pieces, one pillar. Baton's agent side isn't a scattering of tricks. It's one connected capability: the MCP control server (the interface), audio focus (so another app can duck the music and hand it back politely), the menu-bar controller (which keeps Baton and the server reachable even with every window closed), and spoken summaries (so the agent can talk back). Together they mean an agent can connect, steer playback, duck around your dictation, and speak a result aloud, all with no window open.
Connecting a client
The server runs automatically while Baton is open, so there's nothing to switch on. When it starts, Baton writes a discovery file with everything a client needs at ~/Library/Application Support/Baton/mcp.json:
{
"schemaVersion": 1,
"name": "baton",
"transport": "streamable-http",
"url": "http://127.0.0.1:8787/mcp",
"token": "b7f3c0…a1c9",
"app": { "bundleId": "io.tonebox.baton", "version": "0.6.x" }
}
Point a client at the url over the Streamable HTTP transport and pass the token as a bearer token. In Claude Code that's one command:
claude mcp add --transport http baton \
http://127.0.0.1:8787/mcp \
--header "Authorization: Bearer <token-from-mcp.json>"
For Claude Desktop, or any client that uses an mcpServers config block:
{
"mcpServers": {
"baton": {
"type": "http",
"url": "http://127.0.0.1:8787/mcp",
"headers": { "Authorization": "Bearer <token-from-mcp.json>" }
}
}
}
mcp.json, shows it in that Port field and posts a notification naming the new port. Always read the current url and token from the file. Baton has to be running for the server to be live, which is what the menu-bar item is for.
The tools
The server exposes 41 music operations, the same actions Baton's own UI uses.
Search & play
| Tool | What it does |
|---|---|
music_search | Search songs, albums, and artists |
music_play | Play a search now, replacing the queue |
music_play_next | Insert matches right after the current track |
music_queue_add | Add matches to the end of the queue |
music_play_playlist | Play one of your playlists |
music_start_radio | Endless “more like this” from a track or search |
music_build_mix | Build a mix to a target length, then queue or save it |
Explore the library
Searching answers “is this in here”. These answer “what is in here”, which is what a recommendation has to start from.
| Tool | What it does |
|---|---|
music_list_genres | The genres in your library, with song counts |
music_browse_albums | Albums by kind: random, newest, most-played, liked, by genre or year |
music_similar_songs | Real neighbours of a track or artist, not a keyword match |
music_discover_external | Music you don’t have yet, from public catalogues. Off unless you turn it on |
music_liked | Your liked songs, albums, and artists |
music_random | Random songs, optionally within a genre or year range |
music_artist_info | An artist’s biography and every album of theirs you have |
music_transcript | What was said in a spoken track, timed. Returns a window, not the whole hour |
music_summarize_track | An episode’s summary and its timestamped chapter marks |
Control playback
| Tool | What it does |
|---|---|
music_pause / music_resume / music_stop | Pause, resume, or stop |
music_next / music_previous | Skip forward or back |
music_seek | Jump to a position in the current track |
music_set_volume | Set Baton's volume, 0 to 100 |
music_set_repeat / music_set_shuffle | Repeat (off/all/one) and shuffle |
music_sleep_timer | Pause after some minutes |
music_set_crossfade | Crossfade length between tracks in seconds (0 is off) |
Queue, rating & playlists
| Tool | What it does |
|---|---|
music_get_queue | Return the queue with positions |
music_reorder_queue / music_remove_from_queue | Move or remove a queued track |
music_like | Like or unlike a track |
music_rate | Set a 1 to 5 star rating |
music_create_playlist / music_add_to_playlist | Create a playlist or add to one |
music_delete_playlist / music_list_playlists | Delete or list playlists |
music_get_playlist | Read one playlist’s tracks |
music_share | Make a link a friend outside your network can play in a browser. Refuses until you’ve shared a song once yourself (see Sharing a song) |
Report & sound
| Tool | What it does |
|---|---|
music_now_playing | Report the current track, state, and queue position |
music_recent_events | What was played recently and how long each was heard before moving on, including skips |
music_set_eq | Turn the equalizer on/off and apply a preset |
Meeting interpretation routes
Tonebox captures and translates the call. Baton plays two independent directions through headphones and an installed virtual microphone. Select that virtual microphone in the meeting app. Interpreter audio uses authenticated local streams; ordinary agent announcements wait until interpretation ends. Muting a direction invalidates its audio; resuming never replays old speech.
| Tool | What it does |
|---|---|
interpretation_devices | List stable audio device identifiers and route capabilities |
interpretation_open | Open independent headphone and virtual microphone routes |
interpretation_status | Read connection state and lane generations |
interpretation_configure | Resume one stopped lane with a new generation; never replay prior speech |
interpretation_cancel | Immediately invalidate and mute one direction |
interpretation_close | Stop both directions and release music focus |
The rest of the app
Listed on the control server only, not in the in-app chat. The tools that delete, revoke, share or replace something change nothing unless the agent passes confirm: true; without it they say what they would do. None returns a link, key, feed or stream address, file path or server address, except share_mixtape, which hands the link it has just made to the agent that asked for it.
| Tool | What it does |
|---|---|
books_list | The books in Books: chapters made, where the listener is, finished, narrator, cover and cast. Listed while Documents is on |
book_chapters | One book's chapters and whether each is ready |
book_play | Play a book from the listener's place, or from a chosen chapter |
book_cast | A book's narrator and, for voiced dialogue, each character's voice |
book_change_voice | Make a book again in another narrator's voice. Needs confirm |
book_cover | Make a cover from the title and author, or remove the cover. Needs confirm |
clippings_list | The saved readings in Clippings, newest first |
clipping_play | Play a clipping |
clipping_delete | Delete a clipping here, or on every device. Needs confirm |
podcasts_list | The shows you follow by feed, with unplayed counts |
podcast_episodes | A show's episodes and how far you got |
podcast_play_episode | Play an episode, by default the newest unplayed |
podcast_subscribe | Follow a show by its feed address. Needs confirm |
podcast_unsubscribe | Stop following a show. Needs confirm |
radio_list_stations | Your internet radio stations and the one on air |
radio_play_station | Play a station |
later_list | What is on Later |
later_add | Save a song to Later, by default the one playing |
later_remove | Take something off Later. Needs confirm |
later_play | Play something on Later |
history | Your latest plays, or your most-played tracks, albums or artists |
downloads_list | What is downloaded, the space it takes, and offline mode |
download_songs | Download songs for offline listening |
download_remove | Remove downloaded songs from this Mac. Needs confirm |
shares_list | The song links and mixtapes you shared, without the links |
share_revoke | Stop a shared link or mixtape playing for everyone. Needs confirm |
share_mixtape | Share 2 to 12 songs as one mixtape link. Needs confirm |
handoff_status | Whether another device left a queue to pick up, and the linked devices |
handoff_accept | Pick up the queue another device left |
handoff_save_queue | Leave this Mac's queue for your other device. Needs confirm |
playback_speed | Read or set the speed podcasts and books play at |
settings_read | What is set up and the playback, books and speech choices, never an address or key |
Live resources
Baton also publishes five read-only views a client reads once and is then notified about when they change, so an agent can follow along without polling. These are addresses an agent reads through the control server, not links you can open:
| Resource | What it holds |
|---|---|
baton://now-playing | Current track, state, position, volume |
baton://queue | The full queue and current index |
baton://library/playlists | Your playlists |
baton://library/liked | Your liked songs, albums, and artists |
baton://history/recent | Recently played, plus top tracks and artists |
Audio focus & speaking aloud
Two more operations, audio_suspend and audio_resume, let another app duck or pause Baton politely and bring it back. This is how Tonebox lowers the music while you dictate, then restores it, but only if you didn't change playback yourself in the meantime. And speak_summary lets an agent have Baton read a short result aloud in a natural voice (see Spoken summaries).
How it's secured: the control server listens only on your own machine (loopback, 127.0.0.1), so it isn't reachable from your network, and every request must present the secret token Baton generates. The token is compared in constant time, and the mcp.json that carries it is readable only by you. Both are required together.
music_* operations (including music_build_mix), the audio_suspend / audio_resume focus hand-off, and speak_summary; publishes five live resources; and writes the mcp.json discovery file with the endpoint URL and token. A menu-bar controller ships too.
Control Baton from Telegram or Discord
Baton can take commands from a chat app, so the stereo answers to your phone from the couch, the kitchen, or the other end of a train line. Set it up in Settings → Remote.
Telegram, step by step
- In Telegram, message @BotFather (Telegram's official bot-maker: look for the verified checkmark) and send
/newbot. - Give it a display name, then a username ending in
bot. - BotFather replies with a token like
8123456789:AAF3k9…. Treat it like a password. - In Baton: Settings → Remote, turn on Enable remote control and Enable Telegram, paste the token, click Save. Status turns green with your bot's
@name. - Message your bot
/link 123456using the six-digit code from the pane's Linking section. It replies “Linked.”
Group chats: Telegram bots default to privacy mode in groups: np goes unseen while /np gets through. Use /-commands in groups, or turn privacy off via BotFather's /setprivacy. /pause@your_bot disambiguates when several bots share a group.
Discord, step by step
The order matters: the Message Content intent comes before the token, because without it Discord strips the text out of your messages. The bot connects fine and appears to ignore everything, with no error anywhere.
- At discord.com/developers/applications, click New Application and name it.
- Open Bot in the sidebar and set three things: Public Bot off; Message Content Intent on (under Privileged Gateway Intents, then Save Changes); Reset Token and copy it (shown once).
- In Baton: Settings → Remote, enable remote control and Discord, paste the token, Save. Status turns green when the connection is up.
- Invite the bot to a server: copy the Application ID from General Information, then open
https://discord.com/oauth2/authorize?client_id=YOUR_APPLICATION_ID&permissions=68608&scope=bot
and pick your server.68608= View Channels + Send Messages + Read Message History, and nothing more: no Administrator, no Manage-anything. (No server? Create a private one with Discord's + button.) - Pick or create a channel. Baton ignores messages written by bots, so it can share a channel with webhook feeds.
- Send
/link 123456there, with the code from Baton's Linking section.
To confine the bot to particular channels, put channel ids into Limit to channels (get an id via Discord Settings → Advanced → Developer Mode, then right-click a channel → Copy Channel ID). Optional: the link-code allowlist is what actually guards access.
Why the link code
A bot token identifies the bot, not you, so Baton doesn't treat it as permission. Anyone who found your bot could otherwise message it and take over your speakers. Until a chat is linked Baton ignores everything it's sent, and each code works only once, because you're typing it into a chat history. After five wrong codes Baton stops accepting any until you press New code. Linked chats are listed in the Remote pane with a Revoke button.
What you can say
Ordinary messages; the leading slash is optional.
| Message | What it does |
|---|---|
play kind of blue | Search the library and play the best match |
pause · resume · stop | The obvious ones |
next · prev | Skip forward or back |
queue radiohead | Add matches to the end of the queue |
vol 40 | Volume 0-100 (Baton's own, not the Mac's) |
seek 1:30 | Jump to a position |
np | What's playing right now |
like · rate 5 | Star or rate the current track |
playlists · playlist Evening | List playlists, or play one (part of the name is enough) |
mix upbeat focus | Build a mix from a description |
radio | Endless “more like this” |
sleep 30 | Pause in 30 minutes (sleep off cancels) |
forget | Clear what this chat remembers |
help | The full list, in the chat |
Replies carry buttons for the common actions, so skipping a track is a tap rather than a typed word.
Saying it in your own words
Turn on Understand plain English and anything Baton doesn't recognize as a command is read as intent instead: “put on something mellow”, “make me a 40-minute driving mix”. This needs a model to talk to, which you provide; Baton ships no key and the feature stays off until you set it up. A Test button sends one real request and tells you whether it worked.
Baton speaks two API dialects, which between them cover nearly everything:
- Anthropic: Claude's Messages API.
- OpenAI-compatible: the
chat/completionsshape served by OpenAI, Groq, Together, Mistral, DeepSeek and OpenRouter, and by self-hosted vLLM, Ollama, LM Studio, llama.cpp and LiteLLM. Pick this one for a model running on your own hardware.
Your own model. Set the provider to OpenAI-compatible, put your server's address in API base URL (the root that /chat/completions hangs off, e.g. http://your-server:8000/v1, or http://localhost:11434/v1 for Ollama) and set Model to whatever name it serves. Nothing leaves your network and there's no per-message cost. The one requirement is that the model supports tool calling: Baton asks it to pick from a list of commands, and a model without that support fails the Test with an error saying so.
Commands are tried first, but they don’t trap you. A message starting with a command word is handled instantly and locally: play kind of blue is a search, not a question for the model. If that literal reading finds nothing and plain English is on, Baton asks the model what you meant instead of leaving you with “no songs matched”, so play the second one works even though it starts with play.
Follow-ups work. Each chat remembers its last few exchanges, so “show me tracks for Dido” followed by “play the second one” does what you’d expect. That memory lives only while Baton runs, covers a few recent exchanges, expires after about half an hour of quiet, and is separate per chat. Send forget to clear it.
What goes to the model. With each message, Baton sends the model provider you chose what you typed, the chat's last few exchanges, the list of Baton's own commands, and what's playing now (its title, artist, album and place in the queue). It never sends your server credentials. With Let it look around first on, more goes with it, as described below. Under the hood the model picks from the same control surface an agent gets, so a sentence can't ask Baton to do anything the buttons can't; deleting a playlist is deliberately out of reach for it.
Letting it look around first
Underneath is a second switch, Let it look around first, and it is the difference between a translator and something you can have a conversation with.
Off, your sentence becomes one command chosen blind. Baton looks nothing up for the model, so apart from what’s playing and the chat’s last few messages it knows nothing about your library, and it has to be right first time. Ask for “lazy music” and you get “nothing matched”, even though the chillout is right there tagged chill, lounge and ambient, because a mood is rarely a song title.
On, Baton lets it look before it answers. It can read which genres your library actually uses, what you have liked and played most, what is similar to a track, and which albums are newest or most-played, then search again with words it has seen work, and play the result. The reply says what it did and why it is not literally what you asked: “nothing called ‘lazy’: your chillout is tagged chill, playing that”.
It asks when asking is the honest thing. If what it found splits two ways and the answer changes what you would hear (two artists sharing a name, a six-hour mix beside a forty-minute set), it offers them as buttons, each with the fact that decides it. Tap one, or type 2, or say “the ambient one”. Ignore it and after a minute or so it starts the one it recommended and tells you so, rather than leaving you in silence. Send anything else and the question is dropped, so nothing starts playing under you after you have moved on.
It costs a little more than one request per message, since looking takes turns. Against a local model that is typically a second or two.
It knows what you listen to. Before it answers, Baton hands it a dozen lines read from your own server: biggest genres with counts, what you have played most and how often, how many songs you have liked, what you added recently. Nothing stored, nothing guessed; the server’s own numbers, read fresh each day. That is what makes “what kind of music do I listen to?” answerable and “surprise me” grounded in your collection.
It occasionally has a view: when a number is worth mentioning it says so in passing, then does what you asked anyway. It never refuses, and mentions any one thing at most once a day.
What it remembers
Some things your server cannot know: that you do not want vocals while you work, that the gothic playlists are your partner’s, that “my trance” means the Classic Trance ones. Tell Baton and it keeps them, in a plain file you can open.
- It stores your words, not its impressions. Every memory carries the sentence you actually said. There is nowhere to put “seems to like sad music on Sundays”: the file has no field for a guess about you.
- It tells you every time it writes one, in the same window a second later. One message fixes a misunderstanding.
- One command away.
memorieslists everything with its quote,forget 2removes one,forget everythingclears the lot. Settings has a switch and a delete-all button, and the Friend Log shows them too.
Backing up and restoring your settings
On the Mac you can save Baton's settings to a file and bring them back later, on the same Mac, a new one, or your iPhone. Your likes, ratings, playlists and play counts don't need this: they live on your music server.
Exporting your settings
Open Settings → About → Back up & restore and click Export…. The sheet has one choice, Include accounts & passwords, which starts off.
- Off, the file holds your preferences: playback and sound choices, the equalizer, speech and book settings, webhook actions and the rest. It leaves out your queue, your play history and where your downloads are kept. Nothing in it is secret, so it is not encrypted.
- On, it also holds your music server passwords, your Last.fm and ListenBrainz sign-ins, your Baton server token, the music friend's API key, the keys for finding music you don't have, and what the friend remembers and has learned. Then the whole file is encrypted with a passphrase you choose. Keep the passphrase somewhere safe: without it the file can't be opened.
Baton doesn't keep a copy anywhere itself. The exported file is yours to store where you like.
Importing your settings
On the Mac, click Import… in the same place and choose the file. If it is encrypted, Baton asks for the passphrase. Then quit Baton and open it again, so every setting takes effect.
The iPhone imports but doesn't export. Open Settings → Music server → Set up from a Mac… and choose Choose an exported file (see Baton on iPhone).
What never travels
Some things stay on the Mac that made them, even in an encrypted export, so you set them up again after an import:
- The agent control token. Baton makes a new one, so reconnect your agent apps with the token in the new
mcp.json(see Agent (MCP) control). - Telegram and Discord bot tokens.
- The header values of your webhook actions.
- The key for an expressive voice server.
- Your identity on Baton's share service, so links you shared stay listed, and can be extended or revoked, only on the device that made them.
If you exported without accounts, you also sign in again to your music server, Last.fm and ListenBrainz, and enter your Baton server token and API keys again.
Updates
On the Mac, Baton updates itself with Sparkle, the usual updater for Mac apps, and installs only builds that are signed and notarized by Apple. It checks on its own unless you turn off Automatically check for updates under Settings → About → Updates, where Check for Updates Now also lives. You can also choose Baton → Check for Updates…, or Check for Updates… in the menu-bar menu.
Download the current release from batonmusic.app and it keeps itself up to date from there. The iPhone app updates through the App Store.
Roadmap
Now in Baton (recently landed): the iPhone app, Alarm and Timer, song, mixtape and book links for friends, audiobooks made from documents, lyrics looked up when your server has none, Podcasts and Internet radio, downloads and offline mode, a parametric equalizer, more than one music server, and the agent-built music_build_mix.
Still ahead (called out so the docs stay honest):
- Casting beyond AirPlay: Chromecast, Sonos, and UPnP/DLNA. (AirPlay works today.)
- Mixes built from the sound itself: tempo, energy and key as well as play history.
- Crossfeed and more sound processing.
FAQ
Is Baton free?
The Mac app is, a give-away from Tonebox. No subscription, no catalogue rent: you're playing music you already own on a server you already run. The iPhone app costs money, and that is what covers the Apple developer account the Mac build is signed and notarized with.
How is Baton different from Tonebox?
They are two products from the same maker. Tonebox is a paid notes app that works on your own machine and records and transcribes meetings and voice notes. Baton is the music player, pulled out into its own free app. Tonebox can control Baton (for example, lowering the music while you dictate), but you don't need Tonebox to use Baton.
What music servers work with Baton?
Navidrome, and any other server that speaks the Subsonic language, which covers most self-hosted music servers. Baton has no catalogue of its own, so there's nothing to browse until you connect a server.
Is my password safe?
Yes. It is kept in the Keychain on your Mac or iPhone, never in a plain file. With a username and password, Baton sends a code made from the password rather than the password itself, the way Subsonic servers expect.
Does Baton phone home?
Baton talks to the music server you point it at, your Baton server if you run one, and, on the Mac, its update feed (checks are on to begin with; turn them off under Settings → About → Updates). Everything else happens only when you set it up or ask for it: scrobbling to ListenBrainz or Last.fm, voice and transcription servers you run, a model provider for the music friend, Telegram or Discord, LRCLIB for missing lyrics, Open Library when you look for a book cover, and Baton's share service when you share a link. Your Baton server keeps the text and audio of your books on that machine until you remove them, and none of it reaches us.
Crash reports are off unless you turn them on: Settings → About → Diagnostics → Send crash & error reports on the Mac, or Send crash reports on the iPhone. Then Baton sends crash and error details to its developer through Crashbox, a crash reporting service, to help fix bugs. It never sends your music, your library, your server address or your account, and no IP address or identifiers. Turning it on means Baton tries to send a report after a crash; it doesn't confirm that the report arrived.
Is the control server a security risk?
No, by design. It listens only on your own Mac, so it can't be reached from your network, and every request must carry a secret token Baton makes. Both are required.
Do I need an agent to use Baton?
No. Baton is a complete music player on its own. Agent control is optional.
Does Baton work offline?
Yes, for downloaded music. Download tracks, albums, mixes and playlists and play them without streaming. Downloads (in the sidebar on the Mac, in Library on the iPhone) manages them, with an Offline mode. Browsing and streaming anything new still needs your server.
Can I send a song to a friend who isn't on my server?
Yes. Share… in a song's menu makes a link your friend opens in any browser, encrypted on your device first. Mixtapes and whole books work the same way. See Sharing a song with a friend.
How do I get my Mac's settings onto my iPhone?
Scan a pairing code from the Mac, or import a file you exported on the Mac. See Setting it up from your Mac and Backing up and restoring your settings.
Can I cast to speakers?
AirPlay works today, from the AirPlay picker: in the now-playing bar on the Mac, and in the full player on the iPhone. Chromecast, Sonos and UPnP/DLNA are planned.
What platforms does Baton run on?
macOS (15 or later), and iPhone (iOS 18 or later) as Baton: Navidrome Music Player on the App Store. Windows and Linux apps are not planned.