Last active
October 10, 2025 07:11
-
-
Save drewkerr/0f2b61ce34e2b9e3ce0ec6a92ab05c18 to your computer and use it in GitHub Desktop.
Read the current Focus mode on macOS Monterey (12.0+) using JavaScript for Automation (JXA)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const app = Application.currentApplication() | |
| app.includeStandardAdditions = true | |
| function getJSON(path) { | |
| const fullPath = path.replace(/^~/, app.pathTo('home folder')) | |
| const contents = app.read(fullPath) | |
| return JSON.parse(contents) | |
| } | |
| function run() { | |
| let focus = "No focus" // default | |
| const assert = getJSON("~/Library/DoNotDisturb/DB/Assertions.json").data[0].storeAssertionRecords | |
| const config = getJSON("~/Library/DoNotDisturb/DB/ModeConfigurations.json").data[0].modeConfigurations | |
| if (assert) { // focus set manually | |
| const modeid = assert[0].assertionDetails.assertionDetailsModeIdentifier | |
| focus = config[modeid].mode.name | |
| } else { // focus set by trigger | |
| const date = new Date | |
| const now = date.getHours() * 60 + date.getMinutes() | |
| for (const modeid in config) { | |
| const triggers = config[modeid].triggers.triggers[0] | |
| if (triggers && triggers.enabledSetting == 2) { | |
| const start = triggers.timePeriodStartTimeHour * 60 + triggers.timePeriodStartTimeMinute | |
| const end = triggers.timePeriodEndTimeHour * 60 + triggers.timePeriodEndTimeMinute | |
| if (start < end) { | |
| if (now >= start && now < end) { | |
| focus = config[modeid].mode.name | |
| } | |
| } else if (start > end) { // includes midnight | |
| if (now >= start || now < end) { | |
| focus = config[modeid].mode.name | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return focus | |
| } |
I just needed something dead-simple: focus mode on or off. None of the above were working without errors for me on Tahoe, so I adapted the Python example from @roman-ld above (thanks) and stripped out some parts that I don't need.
I saved this as /usr/local/bin/dnd and chmod +x'd it. “Works for me” but YMMV.
With this you can do things like if dnd -q ; then ... ; fi in shell scripts.
#!/usr/bin/env python3
"""
Check DND status - tested only on macOS 26.0 Tahoe
exits with 0 if a focus mode is enabled, 1 otherwise
prints mode unless -q/--quiet is passed as arg
based on https://gist.github.com/drewkerr/0f2b61ce34e2b9e3ce0ec6a92ab05c18
"""
import json
import os
import sys
ASSERTIONS_PATH = os.path.expanduser("~/Library/DoNotDisturb/DB/Assertions.json")
CONFIG_PATH = os.path.expanduser("~/Library/DoNotDisturb/DB/ModeConfigurations.json")
QUIET = False
def msg(m: str, q: bool) -> None:
if not q:
print(m)
def get_focus(q: bool) -> int:
try:
ASSERTION_RECS = json.load(open(ASSERTIONS_PATH))['data'][0]['storeAssertionRecords']
FOCUS_CONFIGS = json.load(open(CONFIG_PATH))['data'][0]['modeConfigurations']
MODE = ASSERTION_RECS[0]['assertionDetails']['assertionDetailsModeIdentifier']
msg(FOCUS_CONFIGS[MODE]['mode']['name'], q)
return 0
except:
msg("No focus", q)
return 1
if '__main__' == __name__:
if len(sys.argv) > 1:
if sys.argv[1] in ['-q', '--quiet']:
QUIET = True
sys.exit(get_focus(QUIET))
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@tooh welcome to macos updates!
Still working for me after upgrading to Tahoe.
I think I've found the problem, have you agreed to the "Xcode and Apple SDKs license" after upgrading?
I looked at what my python3 I was using (
which python3).Found I'm on homebrew for python3 (meaning I didn't have to agree for the python to work).
Used find to find other python3 on my path (
find "${(s/:/)PATH}" -name python3).Aside: Apple's zsh now has several entries that are not readable / search able from a non-admin account (don't worry about these if you run into this as a non-admin user).
When I switched the #! to
#!/usr/bin/python3(macos stock python3) I got:Bottom of that says:
After agreeing (running the -license, typing accept) the script worked with macos stock python3
I hope this helps.