Skip to content
C.W.K.
Stream
Lesson 07 of 08 · published

Restart the Owner on Purpose

~14 min · daemon, restart, launchd, consent, operator

Level 0Spark
0 XP0/48 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

The Owner Needed a Verb

An owner that keeps sessions alive across app quits also has to be replaced sometimes: a new build changes its protocol, a new input contract has to reach it. Until 2026-09-17 that replacement was a hand sequence — quit the app, ask launchd to restart the agent, check that a new owner answered, reopen the app. Dad asked the obvious question: why is this not in the app? Nothing forbade it any more. The previous lesson had just made every pane reconnect and reopen as a shell by itself. The one remaining fact was that a restart ends every job the owner holds. So it became a verb, and the verb asks first.

Consent Is a List

Shell → Restart Session Service… first asks the running owner for its sessions, every page of them, and shows what will end — workflow seats called out by name — before anything happens:

Smolder's confirmation sheet: "Restart the session service and end 3 running sessions?" listing zsh — ~, zsh — ~/Media-Sources and OFFICE — ~, explaining that every job ends, ordinary panes restore their saved launches as new processes, and mobile devices reconnect, with a red "Restart and End 3 Sessions" button and Cancel.
The restart names every session it will end and puts the count on the button.

The wording is the product. Every job in these sessions ends, including running CLIs. Ordinary panes restore their saved launches as new processes in their folders, which may restart commands. Mobile devices reconnect to the new service. The button says the count it will end: Restart and End 3 Sessions. If the owner cannot be asked, the inventory is treated as unknown, never as empty, and the confirmation warns that live jobs may end. Only one restart can be in flight, including its question and its confirmation. It is not reachable from a sibling request, from a phone, or from an isolated test run. It is the operator's verb and nobody else's.

Re-register, Never Kickstart

The first build of the verb restarted the agent the way the hand sequence had: by asking launchd to kill and restart the loaded job. Dad's first press froze every pane and every new tab. Two causes were measured. launchd refused to run the new owner binary at all — "Launch Constraint Violation", then "Unable to get updated LWCR" every ten seconds — because the loaded job was still bound to the launch constraint recorded when it was first registered, and an install had replaced the signed binary underneath it. And the fallback shells opened while the owner was missing kept their keyboard pointed at the attachment they had just released, so they could not type either.

The repair, the same afternoon: the restart now unregisters the job, waits, registers it again from the installed property list (one retry), and waits up to thirty seconds for an owner with a new incarnation to answer. Panes show one reconnecting line, retry every second, and reopen in place. A pane that cannot reach the owner for three seconds asks launchd whether the job is running and re-registers it if not, at most once a minute — a job that is not running owns no PTYs, so that ends nothing. A pane still without an owner after about twenty seconds (five for a brand-new pane) runs a working app-owned shell, labeled. The fallback shells got their own keyboard back, and a test now types into them.

Who Is Allowed to Restart It

Only the operator. Installing a new app build never restarts a compatible owner; a deploy to other Macs never restarts one either. The installer re-registers an owner that is loaded but not running, and when a running owner is older than the bundle it compares build identities and prints a stale marker instead of acting. The family deploy reports that marker as a fact. The decision to end live jobs stays with the person who owns them.

Ending every job is a verb with a list, a count, and one operator. Re-register the agent rather than kick a loaded job onto a replaced binary, and make every pane find its way back by itself.

Code

One confirmed restart, start to finish·text
Shell -> Restart Session Service...
  1. ask the owner for its sessions (every page)
       query fails -> inventory UNKNOWN, warn that live jobs may end
  2. show what ends, seats named; button = "Restart and End N Sessions"
  3. operator confirms (one restart in flight, ever)
  4. unregister the agent, wait, register it again (one retry)
       never: kick the still-loaded job onto a replaced binary
  5. wait up to 30 s for an owner with a NEW incarnation
  6. every pane: one reconnecting line, retry each second, reopen in place
       ordinary declarations -> new processes in their folders
       workflow seats        -> plain shells, CLI not restarted

not reachable from: sibling door, phone gateway, isolated test runs

when a pane loses its owner without a restart
  3 s unreachable  -> if launchd is not running the job, re-register it
                      (at most once a minute; a stopped job owns nothing)
  ~20 s (5 s new)  -> app-owned shell, labeled

External links

Exercise

Pick a background service you restart by hand. Write the confirmation you would want before it ends anything: what it lists, what it says will come back and how, what the button says. Then write what the service's clients do while it is gone, second by second, so that none of them is left unable to work when it returns.
Hint
A confirmation that says "are you sure?" without the list is a guess. A client that waits forever for the old process is a dead pane in another costume.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.