/mac-systems
macOS systems specialist — AppKit NSPanel architecture, launchd services, socket activation, MCP bridge resilience, syspolicyd, high-frequency SwiftUI dashboards. Triggers: menu-bar apps, LaunchAgents, Gatekeeper/TCC, UDS/MCP bridges, 10Hz+ SwiftUI.
$ golems-cli skills install mac-systemsUpdated 6 days ago
macOS systems specialist for low-level AppKit, launchd, security policy, resilient networking, and SwiftUI dashboard architecture.
When to Use
- Building or fixing menu bar apps (NSStatusItem, NSPanel, NSPopover migration)
- Configuring LaunchAgents/LaunchDaemons
- Debugging syspolicyd, Gatekeeper, TCC, or codesigning issues
- Implementing resilient Unix Domain Socket bridges (especially for MCP)
- Architecting high-frequency SwiftUI dashboards (10Hz+) on macOS
- Working with launchd socket activation for zero-downtime restarts
Mechanical Environment Truths (hard-won — gen-12 weave E14)
One-liners every worker and launchd plist author must internalize:
- Tailnet IP bind ban — NEVER hardcode tailnet IPs in launchd plists or worker-prompt URLs. Bind
127.0.0.1/ loopback or resolve at start. Three live catches: Phoenix phantom listener (two eras), W10 dead:8852URL. - Codex detached-child reap — Codex
execreaps detached children (&/nohupdie).launchctl submitis the surviving detach path; clean up leftover runners after. - pipefail + early-exit consumer — Under
set -o pipefail, piping into an early-exit consumer (awk '{exit}') SIGPIPE-kills the producer (exit 141). Buffer first, then consume. See/shell-hardening. - zsh read-only specials — Never use zsh read-only specials (
status, etc.) as variable names. - nvm FUNCNEST in profiles —
voicelayer-profilenodehits nvm_lazy_nvmFUNCNEST recursion — use bun for profile scripts. - CloudStorage read bounds — Bound any read of
~/Library/CloudStorage— cloud-only placeholders hang naivetar/read. - Host-identity check first — Machine-named tasks: verify current-host vs target-host identity BEFORE acting ("What you're on is the M4 Max. I was asking about the M1 Pro.").
- Computer-use fallback ladder — When CU fails on a UI element: element click → coords →
osascriptSystem Events AX → keystroke. - footprint, not RSS, for leak watches — RSS is a liar under the macOS memory compressor: a leak sampler showed RSS bouncing 444–760MB while footprint sat at 5.1G. Leak watches and escalation thresholds MUST read phys_footprint (
/usr/bin/footprint <PID>), neverps -o rss. Recipe in Core Knowledge §10.
Core Knowledge
1. Menu Bar App Architecture (NSPopover → NSPanel)
NSPopover is wrong for dashboard-class UIs. It causes:
- White flash on Sonoma/Sequoia/Tahoe (Apple regression in popover composition)
- No resize persistence
- View hierarchy teardown on every dismiss (kills @State)
- No right-click, drag, modifier-click, or programmatic show/hide
The correct primitive: NSStatusItem + custom NSPanel + NSHostingView.
Every serious menu-bar app uses this: Ice, Stats, Raycast, 1Password mini, Bartender, iStatMenus, CleanShot X, Alfred, MonitorControl.
NSPanel Recipe
final class DashboardPanel: NSPanel {
init<V: View>(rootView: V) {
super.init(
contentRect: NSRect(x: 0, y: 0, width: 520, height: 620),
styleMask: [.titled, .closable, .resizable, .fullSizeContentView,
.nonactivatingPanel, .utilityWindow],
backing: .buffered, defer: false
)
titlebarAppearsTransparent = true
titleVisibility = .hidden
isFloatingPanel = true
level = .statusBar
hidesOnDeactivate = false
becomesKeyOnlyIfNeeded = true
collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary, .transient]
animationBehavior = .utilityWindow // THE flash fix
isMovableByWindowBackground = false
hasShadow = true
isOpaque = false
backgroundColor = .clear
let effect = NSVisualEffectView()
effect.material = .menu
effect.state = .active
effect.blendingMode = .behindWindow
effect.wantsLayer = true
effect.layer?.cornerRadius = 10
effect.layer?.masksToBounds = true
let host = NSHostingView(rootView: rootView)
host.sizingOptions = [.preferredContentSize]
host.translatesAutoresizingMaskIntoConstraints = false
effect.addSubview(host)
NSLayoutConstraint.activate([
host.leadingAnchor.constraint(equalTo: effect.leadingAnchor),
host.trailingAnchor.constraint(equalTo: effect.trailingAnchor),
host.topAnchor.constraint(equalTo: effect.topAnchor),
host.bottomAnchor.constraint(equalTo: effect.bottomAnchor),
])
contentView = effect
}
override var canBecomeKey: Bool { true }
override var canBecomeMain: Bool { false }
}Seven Anti-Flash Measures
animationBehavior = .utilityWindow— subtle fade instead of scale-in- Pre-create panel at launch, not on first click
setContentSize(...)before firstmakeKeyAndOrderFrontisOpaque = false+backgroundColor = .clear+NSVisualEffectViewwantsLayer = trueon hosting viewclipsToBounds = trueon Sonoma+NSHostingView.sizingOptions = [.preferredContentSize](macOS 13.3+)
Style Mask Configurations
| Role | styleMask | level | collectionBehavior |
|---|---|---|---|
| Inspector panel (default) | .nonactivatingPanel, .utilityWindow, .titled, .closable, .resizable, .fullSizeContentView | .statusBar | .canJoinAllSpaces, .fullScreenAuxiliary, .transient |
| Tear-off floating window | Same minus .utilityWindow | .floating | .canJoinAllSpaces, .fullScreenAuxiliary (no .transient) |
| Search HUD (Cmd+K global) | .nonactivatingPanel, .hudWindow, .fullSizeContentView | .floating | .canJoinAllSpaces, .stationary |
MenuBarExtra Verdict
.menustyle blocks the runloop — timers pause, Combine freezes. Ruinous for live data..windowstyle is backed by NSPopover with all its problems.- Use MenuBarExtra only for the Settings scene.
2. State Architecture for Live Dashboards
Update Coalescing (Cap UI Writes at 20 Mutations/Second)
actor UpdatePump<Event: Sendable> {
private var pending: [Event] = []
private var scheduledFlush: Task<Void, Never>?
private let apply: @MainActor @Sendable ([Event]) -> Void
init(apply: @escaping @MainActor @Sendable ([Event]) -> Void) {
self.apply = apply
}
func enqueue(_ event: Event) {
pending.append(event)
guard scheduledFlush == nil else { return }
scheduledFlush = Task { [weak self] in
try? await Task.sleep(for: .milliseconds(50))
await self?.flush()
}
}
private func flush() async {
let batch = pending
pending.removeAll(keepingCapacity: true)
scheduledFlush = nil
guard !batch.isEmpty else { return }
await apply(batch)
}
}Make apply perform one MainActor mutation per batch (for example, reduce the
events into one dashboard snapshot before assigning it). The single scheduled
task bounds flushes to one every 50 ms; merely buffering events and exposing an
unthrottled flush() does not enforce a rate cap.
Persistence Primitives
| What | How |
|---|---|
| Window frame | panel.setFrameAutosaveName("PanelName") |
| Tab selection | @AppStorage("selectedTab") with RawRepresentable enum |
| Complex prefs | sindresorhus/Defaults with @ObservableDefaults |
| Scroll position | @Observable model owns scrollID, bind via .scrollPosition(id:) |
3. LaunchAgents & LaunchDaemons
Key Differences
| LaunchAgent | LaunchDaemon | |
|---|---|---|
| Runs as | Current user | root (or specified user) |
| Plist location | ~/Library/LaunchAgents/ | /Library/LaunchDaemons/ |
| GUI access | Yes | No |
| Loaded by | launchctl bootstrap gui/<uid> | launchctl bootstrap system/ |
Essential Plist Keys
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.example.myservice</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/myservice</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/tmp/myservice.stdout.log</string>
<key>StandardErrorPath</key>
<string>/tmp/myservice.stderr.log</string>
</dict>
</plist>See mechanical truth #1 (loopback bind) and #2 (launchctl submit for Codex detach).
Bun Environment Loading
launchd starts jobs from /, not the package directory. Bun entry points that
depend on a repository environment loader must make it their first import
(adjust the relative path as needed):
import "../lib/load-env";launchctl Commands (macOS 10.10+)
# Load
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.myservice.plist
# Unload (the persistent stop for the current domain session)
launchctl bootout gui/$(id -u)/com.example.myservice
# Status
launchctl print gui/$(id -u)/com.example.myservice
# Start or cycle without unloading
launchctl kickstart gui/$(id -u)/com.example.myservice
launchctl kickstart -k gui/$(id -u)/com.example.myservice
# Send SIGTERM. With KeepAlive=true, launchd relaunches it; this cycles, not stops, the job.
launchctl kill SIGTERM gui/$(id -u)/com.example.myservice
# Detached one-shot (survives Codex exec reap — preferred over bare nohup &)
launchctl submit -l com.example.oneshot -- /path/to/script.sh4. Socket Activation via launchd
The kernel mechanism:
- launchd creates and holds the socket (not the daemon)
- When a connection arrives, launchd starts the daemon
- If daemon crashes, launchd keeps the socket open — connections queue until new daemon starts
- API:
launch_activate_socket()(XPC framework)
<!-- LaunchAgent example: pre-create this parent directory mode 0700, owned by the user. -->
<key>Sockets</key>
<dict>
<key>MySocket</key>
<dict>
<key>SockPathName</key>
<string>/Users/example/Library/Application Support/MyService/myservice.sock</string>
<key>SockPathMode</key>
<integer>384</integer>
</dict>
</dict>Property lists encode the mode in decimal: 384 is 0600. Do not put an
unauthenticated world-writable socket (438 / 0666) in shared /tmp. Replace
example with the LaunchAgent user. For a LaunchDaemon, use a pre-created,
service-owned protected directory such as /var/run/myservice/; broaden the
mode only for an explicit, authenticated cross-user protocol.
Swift side:
import Darwin
func getActivatedSocket(name: String) -> Int32? {
var fds: UnsafeMutablePointer<Int32>?
var count: Int = 0
let result = launch_activate_socket(name, &fds, &count)
guard result == 0, let fds = fds, count > 0 else { return nil }
let fd = fds[0]
free(fds)
return fd
}5. Resilient MCP Bridge Patterns
Problem: MCP over stdio is session-scoped. When the stdio process dies, Claude Code marks it "failed" and never retries. No upstream fix exists (issues #43177, #36308, #15232).
Option A: Resilient Adapter (Recommended)
Replace socat STDIO UNIX-CONNECT:/path.sock with a bridge that reconnects:
const SOCK_PATH = "/Users/example/Library/Application Support/MyService/myservice.sock";
let socket = null;
let buffer = [];
let retryDelay = 500;
async function connect() {
while (true) {
try {
socket = await Bun.connect({ unix: SOCK_PATH, socket: handlers });
for (const msg of buffer) socket.write(msg);
buffer = [];
retryDelay = 500;
return;
} catch {
await Bun.sleep(Math.min(retryDelay *= 2, 30000));
}
}
}
// On socket error: buffer pending, reconnect
// On reconnect: replay MCP initialize handshake, then flush bufferOption B: launchd Socket Activation
OS holds the socket — zero-downtime restarts. See section 4.
Option C: mcpmon Proxy
Transparent stdio proxy that buffers during restart. Designed for hot-reload but adaptable.
6. Security — syspolicyd, Gatekeeper, TCC
syspolicyd Troubleshooting
# Check if binary is allowed
spctl --assess --verbose /path/to/binary
# Check codesign
codesign -dvvv /path/to/binary
# Watch syspolicyd in real time
/usr/bin/log stream --predicate 'subsystem == "com.apple.syspolicy"' --level debug
# ⚠️ In scripted zsh, ALWAYS invoke /usr/bin/log absolutely — zsh has a `log` builtin that
# shadows it and exits 0 with no output, silently fabricating "no log entries" conclusions.
# Re-assess without reading or writing the assessment object cache
spctl --assess --verbose --ignore-cache --no-cache /path/to/binaryTCC (Transparency, Consent, and Control)
# Check the current TCC database (Requires Full Disk Access for the shell/terminal)
sqlite3 ~/Library/Application\ Support/com.apple.TCC/TCC.db \
"SELECT service, client, auth_value FROM access"
# Reset TCC for an app
tccutil reset All com.example.myappCommon Issues
- "not valid for use in process" error: Binary needs ad-hoc signing:
codesign -s - /path/to/binary - Gatekeeper quarantine: Remove with
xattr -d com.apple.quarantine /path/to/binary - Sandboxed UDS access: Socket must be in an accessible path (not inside another app's container)
7. Visual Effect Materials for Menu Bar Apps
| AppKit Material | SwiftUI Equiv | Use Case |
|---|---|---|
.menu | .thinMaterial | Default panel background |
.popover | .regularMaterial | Alt if .menu too light |
.hudWindow | .thickMaterial | Ephemeral toasts |
.sidebar | .regularMaterial | Left rail |
Always respect @Environment(\.accessibilityReduceTransparency) — swap effect for solid Color("Surface") when set.
8. Keyboard Shortcuts
Use sindresorhus/KeyboardShortcuts (2.6k+ stars, MAS-compatible) for global hotkeys:
import KeyboardShortcuts
extension KeyboardShortcuts.Name {
static let togglePanel = Self("togglePanel",
default: .init(.b, modifiers: [.command, .shift]))
}
// In AppDelegate:
KeyboardShortcuts.onKeyUp(for: .togglePanel) { [weak self] in
self?.togglePanel()
}
// In Settings:
KeyboardShortcuts.Recorder("Toggle Panel", name: .togglePanel)Use .keyboardShortcut() for in-panel shortcuts, .onKeyPress() (macOS 14+) for custom key handling.
9. Deployment Targets (2026)
- Minimum: macOS 14 Sonoma (Observation + .onKeyPress)
- Compile against: macOS 26 SDK
- Gate Tahoe features:
if #available(macOS 26, *)forNSGlassEffectView,.glassEffect(), SF Symbols 7 Draw On/Off - Do not require Tahoe — Sonoma/Sequoia users will be majority through 2027
10. Memory Leak Watches — footprint, not RSS
The macOS memory compressor masks leaks from RSS: compressed pages leave the
resident set but still count against the process's physical footprint (and its
jetsam limit). Observed divergence (2026-06-07 cmux leak watch): RSS bounced
444–760MB while footprint sat at 5.1G — an RSS-based watch nearly suppressed
the escalation. The canonical metric is phys_footprint, read via
/usr/bin/footprint (summary line: name [pid]: 64-bit Footprint: NNNN KB).
Watch-rebuild recipe — threshold on footprint bytes, never ps -o rss:
# Footprint-based leak watch (RSS under-reports under the compressor)
PID=12345; LIMIT_BYTES=$((4 * 1024 * 1024 * 1024)) # escalate at 4 GiB
while kill -0 "$PID" 2>/dev/null; do
fp_bytes=$(/usr/bin/footprint --format bytes "$PID" 2>/dev/null \
| sed -n 's/.*Footprint: \([0-9]*\) B.*/\1/p')
if [ -n "$fp_bytes" ] && [ "$fp_bytes" -ge "$LIMIT_BYTES" ]; then
echo "LEAK: phys_footprint=${fp_bytes}B >= ${LIMIT_BYTES}B" >&2
# escalate here
fi
sleep 60
doneFull SKILL.md source — includes LLM directives, anti-patterns, and technical instructions stripped from the Overview tab.
macOS systems specialist for low-level AppKit, launchd, security policy, resilient networking, and SwiftUI dashboard architecture.
When to Use
- Building or fixing menu bar apps (NSStatusItem, NSPanel, NSPopover migration)
- Configuring LaunchAgents/LaunchDaemons
- Debugging syspolicyd, Gatekeeper, TCC, or codesigning issues
- Implementing resilient Unix Domain Socket bridges (especially for MCP)
- Architecting high-frequency SwiftUI dashboards (10Hz+) on macOS
- Working with launchd socket activation for zero-downtime restarts
Mechanical Environment Truths (hard-won — gen-12 weave E14)
One-liners every worker and launchd plist author must internalize:
- Tailnet IP bind ban — NEVER hardcode tailnet IPs in launchd plists or worker-prompt URLs. Bind
127.0.0.1/ loopback or resolve at start. Three live catches: Phoenix phantom listener (two eras), W10 dead:8852URL. - Codex detached-child reap — Codex
execreaps detached children (&/nohupdie).launchctl submitis the surviving detach path; clean up leftover runners after. - pipefail + early-exit consumer — Under
set -o pipefail, piping into an early-exit consumer (awk '{exit}') SIGPIPE-kills the producer (exit 141). Buffer first, then consume. See/shell-hardening. - zsh read-only specials — Never use zsh read-only specials (
status, etc.) as variable names. - nvm FUNCNEST in profiles —
voicelayer-profilenodehits nvm_lazy_nvmFUNCNEST recursion — use bun for profile scripts. - CloudStorage read bounds — Bound any read of
~/Library/CloudStorage— cloud-only placeholders hang naivetar/read. - Host-identity check first — Machine-named tasks: verify current-host vs target-host identity BEFORE acting ("What you're on is the M4 Max. I was asking about the M1 Pro.").
- Computer-use fallback ladder — When CU fails on a UI element: element click → coords →
osascriptSystem Events AX → keystroke. - footprint, not RSS, for leak watches — RSS is a liar under the macOS memory compressor: a leak sampler showed RSS bouncing 444–760MB while footprint sat at 5.1G. Leak watches and escalation thresholds MUST read phys_footprint (
/usr/bin/footprint <PID>), neverps -o rss. Recipe in Core Knowledge §10.
Core Knowledge
1. Menu Bar App Architecture (NSPopover → NSPanel)
NSPopover is wrong for dashboard-class UIs. It causes:
- White flash on Sonoma/Sequoia/Tahoe (Apple regression in popover composition)
- No resize persistence
- View hierarchy teardown on every dismiss (kills @State)
- No right-click, drag, modifier-click, or programmatic show/hide
The correct primitive: NSStatusItem + custom NSPanel + NSHostingView.
Every serious menu-bar app uses this: Ice, Stats, Raycast, 1Password mini, Bartender, iStatMenus, CleanShot X, Alfred, MonitorControl.
NSPanel Recipe
final class DashboardPanel: NSPanel {
init<V: View>(rootView: V) {
super.init(
contentRect: NSRect(x: 0, y: 0, width: 520, height: 620),
styleMask: [.titled, .closable, .resizable, .fullSizeContentView,
.nonactivatingPanel, .utilityWindow],
backing: .buffered, defer: false
)
titlebarAppearsTransparent = true
titleVisibility = .hidden
isFloatingPanel = true
level = .statusBar
hidesOnDeactivate = false
becomesKeyOnlyIfNeeded = true
collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary, .transient]
animationBehavior = .utilityWindow // THE flash fix
isMovableByWindowBackground = false
hasShadow = true
isOpaque = false
backgroundColor = .clear
let effect = NSVisualEffectView()
effect.material = .menu
effect.state = .active
effect.blendingMode = .behindWindow
effect.wantsLayer = true
effect.layer?.cornerRadius = 10
effect.layer?.masksToBounds = true
let host = NSHostingView(rootView: rootView)
host.sizingOptions = [.preferredContentSize]
host.translatesAutoresizingMaskIntoConstraints = false
effect.addSubview(host)
NSLayoutConstraint.activate([
host.leadingAnchor.constraint(equalTo: effect.leadingAnchor),
host.trailingAnchor.constraint(equalTo: effect.trailingAnchor),
host.topAnchor.constraint(equalTo: effect.topAnchor),
host.bottomAnchor.constraint(equalTo: effect.bottomAnchor),
])
contentView = effect
}
override var canBecomeKey: Bool { true }
override var canBecomeMain: Bool { false }
}Seven Anti-Flash Measures
animationBehavior = .utilityWindow— subtle fade instead of scale-in- Pre-create panel at launch, not on first click
setContentSize(...)before firstmakeKeyAndOrderFrontisOpaque = false+backgroundColor = .clear+NSVisualEffectViewwantsLayer = trueon hosting viewclipsToBounds = trueon Sonoma+NSHostingView.sizingOptions = [.preferredContentSize](macOS 13.3+)
Style Mask Configurations
| Role | styleMask | level | collectionBehavior |
|---|---|---|---|
| Inspector panel (default) | .nonactivatingPanel, .utilityWindow, .titled, .closable, .resizable, .fullSizeContentView | .statusBar | .canJoinAllSpaces, .fullScreenAuxiliary, .transient |
| Tear-off floating window | Same minus .utilityWindow | .floating | .canJoinAllSpaces, .fullScreenAuxiliary (no .transient) |
| Search HUD (Cmd+K global) | .nonactivatingPanel, .hudWindow, .fullSizeContentView | .floating | .canJoinAllSpaces, .stationary |
MenuBarExtra Verdict
.menustyle blocks the runloop — timers pause, Combine freezes. Ruinous for live data..windowstyle is backed by NSPopover with all its problems.- Use MenuBarExtra only for the Settings scene.
2. State Architecture for Live Dashboards
@Observable Over ObservableObject (Mandatory for 10Hz+)
ObservableObject + @Published invalidates every observing view on any property change. @Observable (macOS 14+) tracks per-property reads — only views reading the changed property re-evaluate.
Split state by update frequency:
@Observable @MainActor final class DashboardStats {
var writesPerMinute: Double = 0
var enrichmentsPerMinute: Double = 0
var backlog: Int = 0
}
@Observable @MainActor final class ListModel {
var items: [Item] = []
var selection: Item.ID?
var scrollID: Item.ID?
}
@Observable @MainActor final class AppState {
static let shared = AppState()
let stats = DashboardStats()
let list = ListModel()
}Update Coalescing (Cap UI Writes at 20 Mutations/Second)
actor UpdatePump<Event: Sendable> {
private var pending: [Event] = []
private var scheduledFlush: Task<Void, Never>?
private let apply: @MainActor @Sendable ([Event]) -> Void
init(apply: @escaping @MainActor @Sendable ([Event]) -> Void) {
self.apply = apply
}
func enqueue(_ event: Event) {
pending.append(event)
guard scheduledFlush == nil else { return }
scheduledFlush = Task { [weak self] in
try? await Task.sleep(for: .milliseconds(50))
await self?.flush()
}
}
private func flush() async {
let batch = pending
pending.removeAll(keepingCapacity: true)
scheduledFlush = nil
guard !batch.isEmpty else { return }
await apply(batch)
}
}Make apply perform one MainActor mutation per batch (for example, reduce the
events into one dashboard snapshot before assigning it). The single scheduled
task bounds flushes to one every 50 ms; merely buffering events and exposing an
unthrottled flush() does not enforce a rate cap.
Persistence Primitives
| What | How |
|---|---|
| Window frame | panel.setFrameAutosaveName("PanelName") |
| Tab selection | @AppStorage("selectedTab") with RawRepresentable enum |
| Complex prefs | sindresorhus/Defaults with @ObservableDefaults |
| Scroll position | @Observable model owns scrollID, bind via .scrollPosition(id:) |
3. LaunchAgents & LaunchDaemons
Key Differences
| LaunchAgent | LaunchDaemon | |
|---|---|---|
| Runs as | Current user | root (or specified user) |
| Plist location | ~/Library/LaunchAgents/ | /Library/LaunchDaemons/ |
| GUI access | Yes | No |
| Loaded by | launchctl bootstrap gui/<uid> | launchctl bootstrap system/ |
Essential Plist Keys
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.example.myservice</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/myservice</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/tmp/myservice.stdout.log</string>
<key>StandardErrorPath</key>
<string>/tmp/myservice.stderr.log</string>
</dict>
</plist>See mechanical truth #1 (loopback bind) and #2 (launchctl submit for Codex detach).
Bun Environment Loading
launchd starts jobs from /, not the package directory. Bun entry points that
depend on a repository environment loader must make it their first import
(adjust the relative path as needed):
import "../lib/load-env";launchctl Commands (macOS 10.10+)
# Load
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.myservice.plist
# Unload (the persistent stop for the current domain session)
launchctl bootout gui/$(id -u)/com.example.myservice
# Status
launchctl print gui/$(id -u)/com.example.myservice
# Start or cycle without unloading
launchctl kickstart gui/$(id -u)/com.example.myservice
launchctl kickstart -k gui/$(id -u)/com.example.myservice
# Send SIGTERM. With KeepAlive=true, launchd relaunches it; this cycles, not stops, the job.
launchctl kill SIGTERM gui/$(id -u)/com.example.myservice
# Detached one-shot (survives Codex exec reap — preferred over bare nohup &)
launchctl submit -l com.example.oneshot -- /path/to/script.sh4. Socket Activation via launchd
The kernel mechanism:
- launchd creates and holds the socket (not the daemon)
- When a connection arrives, launchd starts the daemon
- If daemon crashes, launchd keeps the socket open — connections queue until new daemon starts
- API:
launch_activate_socket()(XPC framework)
<!-- LaunchAgent example: pre-create this parent directory mode 0700, owned by the user. -->
<key>Sockets</key>
<dict>
<key>MySocket</key>
<dict>
<key>SockPathName</key>
<string>/Users/example/Library/Application Support/MyService/myservice.sock</string>
<key>SockPathMode</key>
<integer>384</integer>
</dict>
</dict>Property lists encode the mode in decimal: 384 is 0600. Do not put an
unauthenticated world-writable socket (438 / 0666) in shared /tmp. Replace
example with the LaunchAgent user. For a LaunchDaemon, use a pre-created,
service-owned protected directory such as /var/run/myservice/; broaden the
mode only for an explicit, authenticated cross-user protocol.
Swift side:
import Darwin
func getActivatedSocket(name: String) -> Int32? {
var fds: UnsafeMutablePointer<Int32>?
var count: Int = 0
let result = launch_activate_socket(name, &fds, &count)
guard result == 0, let fds = fds, count > 0 else { return nil }
let fd = fds[0]
free(fds)
return fd
}5. Resilient MCP Bridge Patterns
Problem: MCP over stdio is session-scoped. When the stdio process dies, Claude Code marks it "failed" and never retries. No upstream fix exists (issues #43177, #36308, #15232).
Option A: Resilient Adapter (Recommended)
Replace socat STDIO UNIX-CONNECT:/path.sock with a bridge that reconnects:
const SOCK_PATH = "/Users/example/Library/Application Support/MyService/myservice.sock";
let socket = null;
let buffer = [];
let retryDelay = 500;
async function connect() {
while (true) {
try {
socket = await Bun.connect({ unix: SOCK_PATH, socket: handlers });
for (const msg of buffer) socket.write(msg);
buffer = [];
retryDelay = 500;
return;
} catch {
await Bun.sleep(Math.min(retryDelay *= 2, 30000));
}
}
}
// On socket error: buffer pending, reconnect
// On reconnect: replay MCP initialize handshake, then flush bufferOption B: launchd Socket Activation
OS holds the socket — zero-downtime restarts. See section 4.
Option C: mcpmon Proxy
Transparent stdio proxy that buffers during restart. Designed for hot-reload but adaptable.
6. Security — syspolicyd, Gatekeeper, TCC
syspolicyd Troubleshooting
# Check if binary is allowed
spctl --assess --verbose /path/to/binary
# Check codesign
codesign -dvvv /path/to/binary
# Watch syspolicyd in real time
/usr/bin/log stream --predicate 'subsystem == "com.apple.syspolicy"' --level debug
# ⚠️ In scripted zsh, ALWAYS invoke /usr/bin/log absolutely — zsh has a `log` builtin that
# shadows it and exits 0 with no output, silently fabricating "no log entries" conclusions.
# Re-assess without reading or writing the assessment object cache
spctl --assess --verbose --ignore-cache --no-cache /path/to/binaryTCC (Transparency, Consent, and Control)
# Check the current TCC database (Requires Full Disk Access for the shell/terminal)
sqlite3 ~/Library/Application\ Support/com.apple.TCC/TCC.db \
"SELECT service, client, auth_value FROM access"
# Reset TCC for an app
tccutil reset All com.example.myappCommon Issues
- "not valid for use in process" error: Binary needs ad-hoc signing:
codesign -s - /path/to/binary - Gatekeeper quarantine: Remove with
xattr -d com.apple.quarantine /path/to/binary - Sandboxed UDS access: Socket must be in an accessible path (not inside another app's container)
7. Visual Effect Materials for Menu Bar Apps
| AppKit Material | SwiftUI Equiv | Use Case |
|---|---|---|
.menu | .thinMaterial | Default panel background |
.popover | .regularMaterial | Alt if .menu too light |
.hudWindow | .thickMaterial | Ephemeral toasts |
.sidebar | .regularMaterial | Left rail |
Always respect @Environment(\.accessibilityReduceTransparency) — swap effect for solid Color("Surface") when set.
8. Keyboard Shortcuts
Use sindresorhus/KeyboardShortcuts (2.6k+ stars, MAS-compatible) for global hotkeys:
import KeyboardShortcuts
extension KeyboardShortcuts.Name {
static let togglePanel = Self("togglePanel",
default: .init(.b, modifiers: [.command, .shift]))
}
// In AppDelegate:
KeyboardShortcuts.onKeyUp(for: .togglePanel) { [weak self] in
self?.togglePanel()
}
// In Settings:
KeyboardShortcuts.Recorder("Toggle Panel", name: .togglePanel)Use .keyboardShortcut() for in-panel shortcuts, .onKeyPress() (macOS 14+) for custom key handling.
9. Deployment Targets (2026)
- Minimum: macOS 14 Sonoma (Observation + .onKeyPress)
- Compile against: macOS 26 SDK
- Gate Tahoe features:
if #available(macOS 26, *)forNSGlassEffectView,.glassEffect(), SF Symbols 7 Draw On/Off - Do not require Tahoe — Sonoma/Sequoia users will be majority through 2027
10. Memory Leak Watches — footprint, not RSS
The macOS memory compressor masks leaks from RSS: compressed pages leave the
resident set but still count against the process's physical footprint (and its
jetsam limit). Observed divergence (2026-06-07 cmux leak watch): RSS bounced
444–760MB while footprint sat at 5.1G — an RSS-based watch nearly suppressed
the escalation. The canonical metric is phys_footprint, read via
/usr/bin/footprint (summary line: name [pid]: 64-bit Footprint: NNNN KB).
Watch-rebuild recipe — threshold on footprint bytes, never ps -o rss:
# Footprint-based leak watch (RSS under-reports under the compressor)
PID=12345; LIMIT_BYTES=$((4 * 1024 * 1024 * 1024)) # escalate at 4 GiB
while kill -0 "$PID" 2>/dev/null; do
fp_bytes=$(/usr/bin/footprint --format bytes "$PID" 2>/dev/null \
| sed -n 's/.*Footprint: \([0-9]*\) B.*/\1/p')
if [ -n "$fp_bytes" ] && [ "$fp_bytes" -ge "$LIMIT_BYTES" ]; then
echo "LEAK: phys_footprint=${fp_bytes}B >= ${LIMIT_BYTES}B" >&2
# escalate here
fi
sleep 60
doneReferences
- R1 BrainBar UX Research:
$ORCHESTRATOR_ROOT/docs.local/research/R1-claude-desktop-macos-menubar-ux-FULL.md - MCP Reconnection Research:
$ORCHESTRATOR_ROOT/docs.local/research/mcp-reconnection-research.md - Apple:
launch_activate_socket()docs - Community:
jordanbaird/Ice,exelban/stats,sindresorhus/KeyboardShortcuts,sindresorhus/Defaults /shell-hardening— pipefail/SIGPIPE section pairs with mechanical truth #3
Best Pass Rate
100%
Opus 4.6
Assertions
10
5 models tested
Avg Cost / Run
$0.0785
across models
Fastest (p50)
2.7s
Gemini 2.5
Behavior Evals
Phase 2 baseline — skill quality on ClaudeBehavior Baseline
Adapter Evals
Phase 2C — cross-AI portabilityAdapter Portability
| Assertion | Opus 4.6 | Sonnet 4.6 | Haiku 4.5 | Codex | Gemini 2.5 | Consensus |
|---|---|---|---|---|---|---|
| observable-models | 5/5 | |||||
| coalesced-updates | 5/5 | |||||
| surviving-detach | 4/5 | |||||
| loopback-bind | 4/5 | |||||
| no-nohup | 4/5 | |||||
| gatekeeper-tools | 5/5 | |||||
| absolute-log-binary | 5/5 | |||||
| tcc-path | 4/5 | |||||
| physical-footprint | 4/5 | |||||
| rejects-rss-threshold | 4/5 |
Token Usage
Cost per Run
| Model | Input Tokens | Output Tokens | Cost / Run | Cost / 1K Runs |
|---|---|---|---|---|
| Opus 4.6 | 4,163 | 3,050 | $0.2912 | $291.20 |
| Sonnet 4.6 | 1,600 | 1,216 | $0.0230 | $23.00 |
| Haiku 4.5 | 3,190 | 4,296 | $0.0062 | $6.20 |
| Codex | 2,262 | 1,865 | $0.0486 | $48.60 |
| Gemini 2.5 | 2,337 | 1,778 | $0.0236 | $23.60 |
Response Time (p50)
Response Time (p95)
| Model | p50 | p95 | Overhead |
|---|---|---|---|
| Opus 4.6 | 9.4s | 15.3s | +64% |
| Sonnet 4.6 | 3.0s | 5.0s | +69% |
| Haiku 4.5 | 3.6s | 7.1s | +98% |
| Codex | 7.5s | 11.8s | +57% |
| Gemini 2.5 | 2.7s | 5.2s | +91% |
Last evaluated: 2026-03-12 · Data is generated from skill assertions (real cross-model benchmarks coming soon)
Changelog entries are derived from eval runs and skill version updates. Full cascading changelog (Phase 4D) coming soon.
Best Pass Rate
100%
Assertions
10
Models Tested
5
Evals Run
4
- +Initial release to Golems skill library
- +10 assertions across 4 eval scenarios