I'm building a window layout manager that saves and restores window positions across Spaces when switching between display configurations (laptop / docked 3-monitor / Vision Pro). Spencer 1.4.4 handles this today but broke on Golden Gate beta with "Cannot detect number of Spaces." I built a diagnostic probe to find the root cause.
FINDINGS (macOS 27.0 Build 26A5353q):
-
CGSPrivate symbols — all intact and functional: CGSMainConnectionID, CGSCopySpaces, CGSGetWindowWorkspace, CGSMoveWindowsToManagedSpace all resolve via dlsym and work correctly. CGSCopySpaces(mask=7) returns 14 valid space IDs. This is NOT the source of the breakage.
-
com.apple.spaces plist — structure changed in Golden Gate: The top-level 'Monitors' key is gone. It has moved to: SpacesDisplayConfiguration → Management Data → Monitors New top-level keys: [SpacesDisplayConfiguration, app-bindings, spans-displays] This IS the root cause. Spencer's parser looks for 'Monitors', finds nothing, and fails. One-line fix once confirmed stable.
-
CGSGetWindowWorkspace returns Space ID 0 for windows set to 'all desktops'. Valid space IDs in this session are 30, 15, 14, 12, 11, 10 — so 0 appears to be a sentinel value for that condition.
Full probe output:
`SpacesProbe v1.0 — WWDC 2026 Developer Lab ════════════════════════════════════════════════════════ System: Version 27.0 (Build 26A5353q) Date: 2026-06-09 21:41:33 +0000
── PUBLIC API (stable, no entitlements needed) ──────────── ✅ CGWindowListCopyWindowInfo: 17 on-screen windows found ✅ CGGetActiveDisplayList: 1 active display(s) ✅ Accessibility (AXIsProcessTrusted): GRANTED ✅ AXUIElement read: 'Cursor Pro' @ 1427,906 438×438 ✅ AXUIElement write: SUCCESS (nudged window +1px and restored — non-destructive)
── com.apple.spaces PLIST (what Spencer reads to understand Space topology) Path: /Users/csj/Library/Preferences/com.apple.spaces.plist ✅ Plist file exists ✅ Plist readable and deserializable ✅ Monitors in plist: 8 ✅ Total spaces found: 14 Top-level keys: [SpacesDisplayConfiguration, app-bindings, spans-displays] ⚡ GOLDEN GATE: 'Monitors' replaced by 'SpacesDisplayConfiguration' SpacesDisplayConfiguration sub-keys: [Management Data, Space Properties] Monitors (under Management Data): 8 Monitor 0: 14 space(s)
⚠️ 'Monitors' key gone in Golden Gate — moved to SpacesDisplayConfiguration. Spencer parser needs update to read new key.
→ These anomalies cause Spencer 1.4.4 to report → "Cannot detect number of Spaces" on Golden Gate beta.
── CGSPrivate BRIDGE (private API — the only path to Space assignment) Resolution via dlsym — nil = symbol removed from this OS build
✅ CGSMainConnectionID ✅ CGSCopySpaces ✅ CGSGetWindowWorkspace ✅ CGSMoveWindowsToManagedSpace
Connection ID: 3175291 ✅ CGSCopySpaces(mask=7): 14 spaces → 30, 15, 14, 12, 11, 10 ✅ CGSGetWindowWorkspace(wid=99): Space ID = 0
── SUMMARY ───────────────────────────────────────────────── ✅ Window enumeration (CGWindowListCopyWindowInfo): WORKS ✅ Window position read/write (AXUIElement): WORKS ✅ Display topology (CGGetActiveDisplayList): WORKS ❌ com.apple.spaces plist parsing: BROKEN (1 anomalies) ✅ CGSPrivate Space management symbols: ALL PRESENT
Feedback: feedbackassistant.apple.com FB23017010QUESTIONS:
-
Is the new SpacesDisplayConfiguration.Management Data.Monitors path stable and intended for use by third-party tools, or still an implementation detail subject to change?
-
Is Space ID 0 from CGSGetWindowWorkspace the stable sentinel for 'window assigned to all desktops', or is there a proper API for detecting that condition?
-
Is there an entitlement (com.apple.private.spaces or equivalent) that can be granted to productivity tools distributed outside the App Store for Space management?
-
What is the intended supported mechanism for a third-party app to save and restore window Space assignments on macOS?
Feedback: FB23017010
I hate to be the bearer of bad news but…
What is the intended supported mechanism for a third-party app to save and restore window Space assignments on macOS?
As far as I know there are no APIs that let you achieve this goal. It sounds like your existing app relied on a bunch of implementation details, and those are subject to change without notice and, more importantly, without there necessarily being any equivalent replacement.
Feedback: FB23017010
Thanks for that.
That’s likely to get treated as a compatibility bug, although I can’t guarantee that it will result in any changes.
I also recommend that you file an enhancement request for an actual API to achieve what you’re trying to achieve. And if you do file that, please post your bug number, just for the record.
Honestly, it would be good if you could go back in time and file this ER years ago, before you started down the path your on. Sadly, time machines are not a thing )-:
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"