How Stage Manager works in the log

Whether you love it or ignore it, Stage Manager is a major change to the macOS interface, and works its fair share of magic. This article looks briefly at what appears in the Unified log when Stage Manager is in action.

Unlike most other new features in macOS, when Stage Manager is working it doesn’t fill the log with much chatter, leaving that to interconnected subsystems like RunningBoard and SkyLight. Neither does it add lots of new subsystems. This makes its workings relatively easy to identify, at least in terms of major events. If you want a quick summary of relevant log entries, watch the com.apple.windowmanagement subsystem for its distinctive messages.

The log extract below was obtained in a macOS 13.1 virtual machine running in Viable on my Mac Studio M1 Max, also running 13.1. I prefer to use VMs for this type of study now, because their logs are relatively clean compared with a regular Mac. In the log extracts shown, time is given in seconds after an arbitrary starting point, then the subsystem, and the message itself.

Once a mouse or trackpad event to switch what’s on Stage has been passed to Stage Manager, this change in order is reported:
0.911637 com.apple.windowmanagement Ordering <private> above relative to <private>
0.911684 com.apple.windowmanagement App window has been ordered above nil in space 0x1; stage needs to be visible.
0.912456 com.apple.SkyLight 0[SetFrontProcess]: Making 0x0-0x36036 the front process in session 0x186a4

Note how this is recorded as taking place in space 1. In this case, no other spaces were in use. This indicates the depth of integration between Stage Manager and Spaces.

The change is then noted by Launch Services and Process Manager:
0.912700 com.apple.launchservices Adding client pid=139 to access session 100004 because it has euid=0
0.912702 com.apple.launchservices CLIENT: 0x13d004d80/139 Mapped requested session to session id 100004
0.912739 com.apple.processmanager SETFRONT: pid=770 asn=0x-0x36036 foreground=1 oldFrontPid=818 oldFrontASN=0x-0x237626
0.912859 com.apple.launchservices Moving App:"Ulbow" asn:0x0-36036 pid:770 refs=7 @ 0x13bf2b9e0 to front of visible list.

For the sake of simplicity, I only report the first entry written by RunningBoard, which acquires and deals with a succession of assertions, in a long series of log entries.
0.912946 com.apple.runningboard Acquiring assertion: <RBSAssertionDescriptor| "frontmost:770" ID:(null) target:770>

Having brought the app to the front and visible on Stage, LaunchServices gives it the menu bar:
0.913035 com.apple.launchservices Making App:"Ulbow" asn:0x0-36036 pid:770 refs=8 @ 0x13bf2b9e0 into menu bar owning process, oldOwner=App:"StateTest2" asn:0x0-3a03a pid:818 refs=8 @ 0x13bf2ae10
0.913394 com.apple.launchservices LS/CAS: Changed front application to 0x0-0x36036, err=0/noErr

The first of those entries is the clearest statement of the apps involved, here putting Ulbow on Stage, and StateTest2 into the Cast.

Bluetooth services also make it the foreground app:
0.913958 com.apple.bluetooth Foreground App now changed : <private>
0.913963 com.apple.bluetooth Foreground App is now <private>
0.914031 com.apple.bluetooth Foreground app changed :<private>

So far, much of this has been about the app rather than its windows. SkyLight now deals with the windows and pointer (cursor):
0.914361 com.apple.SkyLight 0[SetFrontProcess]: space 1 front connection changed from 3c81b to 2c91b
0.914417 com.apple.SkyLight 0[SetFrontProcess]: requesting window 57 resign key appearance
0.914426 com.apple.SkyLight 0[SetFrontProcess]: requesting window 57 resign main appearance
0.914509 com.apple.SkyLight <private> Taking cursor environment
0.914755 com.apple.SkyLight <private> Showed cursor

Then for the final touches before WindowManagement announces the changed windows on the Stage:
0.915402 com.apple.windowmanagement Setting frontProcessIdentifier=770 frontProcessTimestamp=879006752375
0.915414 com.apple.AppKit BundleID=co.eclecticlight.StateTest2
0.915490 com.apple.AppKit BundleID=co.eclecticlight.Ulbow
0.916021 com.apple.AppKit order window front conditionally: 51 related: 0
0.926213 com.apple.windowmanagement Stage windows did change: <private> -> <private>

Similar principles apply when launching an app onto the Stage, or when quitting an app from the Stage.

The problem with trying to observe Stage Manager’s actions in the log is that almost all WindowManagement entries censor the names of the apps involved, replacing them with <private>. Unless you’re happy to remove the log’s privacy, you’ll need to supplement that subsystem with another that isn’t as shy. My suggestion is to use com.apple.AppKit, in a predicate such as
subsystem = "com.apple.windowmanagement" || subsystem = "com.apple.AppKit"
which spares you a lot of superfluous chatter, but should enable you to make sense of what has gone on. com.apple.launchservices is another candidate, although that does add a lot of entries when launching an app.

Summary

  • Stage Manager is the result of collaborative effort between WindowManagement, Launch Services, SkyLight, RunningBoard and other subsystems in macOS.
  • Stage Manager is deeply integrated with Spaces, even when multiple spaces haven’t been enabled.
  • Although WindowManagement log entries provide detailed information about changes, their value is limited by the almost complete absence of app identification.
  • To obtain a useful account of Stage Manager actions, it’s necessary to supplement log entries from com.apple.windowmanagement with another subsystem such as com.apple.AppKit.