Rest

SwiftUIInteraction

Rest sits in the menu bar and counts down to your next break. Every fourth one is 3 minutes long instead of 30 seconds. My first version used the same white dial as my NTS app. Next to each other on the playground they looked like the same app, so I redesigned it as a landscape and kept the same greys. The panel is white sky over grey land, with the time at the top.

The panel while the clock's running.
The panel while the clock's running.

The thing to look for in the next break stands on the horizon. In this one it's a church. The clock stops when you pause it or when you've been away from the Mac for a minute. After five minutes away it starts over.

When a break starts it covers every screen with the same landscape. On the main one the time left is up in the sky. The thing to look at stands on the horizon, like a church spire or the top of a tree, each with its own pictogram. Skip doesn't work for the first five seconds. Until then it's filled in, and the fill shrinks back from right to left so you can see when it'll work.

A short break, nine seconds in.
A short break, nine seconds in.

In the last minute before a break the notch gets a little wider and counts down to it, a bit like the Dynamic Island on an iPhone. Five seconds out it opens into a warning with a key that pushes the break back five minutes. On a Mac without a notch the warning is a white capsule under the menu bar instead.

The warning five seconds before a short break.
The warning five seconds before a short break.

You'd miss all of that if you were looking at the other side of the screen, so for the last ten seconds a small black disc follows the pointer with the seconds counting down in it. It doesn't take clicks, and near the edge of a screen it moves to the other side of the pointer.

The countdown by the pointer, seven seconds before a break.
The countdown by the pointer, seven seconds before a break.

Calls

If a break comes due while you're on a call, it starts 10 seconds after the call ends, and if a call comes in during a break, the break ends. When a call starts the notch opens with the app's icon and two keys, Ignore till next break and Always ignore. It closes by itself after eight seconds unless the pointer is on it.

The notice when a call starts in Arc.
The notice when a call starts in Arc.

To tell when you're on a call, Rest checks every real microphone through Core Audio. It skips virtual and aggregate devices like Krisp and the one Microsoft Teams installs, because they run whenever their app is open. Each real mic has a flag, kAudioDevicePropertyDeviceIsRunningSomewhere, which changes as soon as any app opens it.

On macOS 14.2 and later Core Audio also has a list of processes. Rest reads which input devices each one is using and gets the app's name from its process ID. Helpers are named after the app they're inside, so a Google Meet call shows up as Google Chrome. Dictation apps like Wispr Flow don't count as a call. Neither does corespeechd, which keeps the mic open for "Hey Siri".

Cameras use the same running flag through CoreMediaIO. For video, Rest checks whether the app in front, or a helper inside it, is keeping the display awake, which is what video players do while they play. None of this records any audio or video, so it doesn't need microphone or camera permission. It can't be sandboxed though, because naming other apps' processes needs proc_pidpath.

Rest is open source on GitHub under the MIT licence.

View project ↗

Posted on 24 October 2026
Permalink, All Playground