A FreeBSD-only port of Apple's notifyd + libnotify — Apple's lightweight named-event pub/sub bus. Retains Mach IPC end-to-end: libnotify connects to notifyd via a MIG-served Mach service com.apple.notifyd; preserves the libnotify C API surface so Apple-derived applications (gershwin desktop apps, ported third-party Cocoa apps) Just Work without source changes. Companion to launchd, configd, kmodloader, asl.
Filed under: freebsd-launchd-mach (v2) effort SHIPPED
This plan originally targeted the sibling freebsd-launchd (AF_UNIX / GNUstep Distributed Objects) repo. Refactored 2026-05-23 to target the freebsd-launchd-mach (v2) Mach-IPC track. notifyd has already SHIPPED in this repo's Phase J1 (libnotify) + Phase J2 iter 1 (notifyd daemon) — Mach IPC retained throughout (DISPATCH_SOURCE_TYPE_MACH_RECV via libdispatch's Mach backend, as documented in the libxpc libdispatch-mach spike). Sections below describing "future work" now describe shipped work; the architecture-decision sentences have been flipped from DO/AF_UNIX to MIG/Mach.
src/Libnotify/, alongside src/launchd/, src/syslog/, src/libxpc/, src/libdispatch/, src/libCoreFoundation/. Single build pipeline (build.sh), single CI, single boot test.notify_post(), notify_register_dispatch(), notify_get_state() — same C API — and the daemon does the fan-out. Promotes cross-process event coordination from "build a bespoke channel each time" to "just pick a name."Libnotify-98.5 (latest tag at apple-oss-distributions/Libnotify, APSL). 48 source files, ~17k LOC. 12 files have <mach/> includes; 2 MIG .defs files (notify_ipc.defs, notify_old_ipc.defs). On the v2 track these are kept — Mach IPC is the substrate.com.apple.system.logger) on every log write; configd, PowerManagement, IPConfiguration, DiskArbitration, IOKitUser all register for / post named events. With Mach IPC + libxpc + libdispatch (incl. DISPATCH_SOURCE_TYPE_MACH_RECV) all working, notifyd lands as a thin MIG server on top of the existing substrate. Built in Phase J1/J2 alongside ASL.notify_ipc.defs); shm_open(2) + mmap(2) for the shared state-value pages (preserves Apple's "reads are zero-IPC" performance characteristic).DISPATCH_SOURCE_TYPE_MACH_RECV on notifyd's MIG service port (the libxpc spike documented why we needed this — libdispatch's Mach backend now provides it on FreeBSD). DISPATCH_SOURCE_TYPE_VNODE for path-watch notifications (same as Apple — pathwatch.c already uses kqueue under the hood).notify_post, notify_register_dispatch, notify_register_signal, notify_register_file_descriptor, notify_register_check, notify_get_state, notify_set_state, notify_cancel all keep their existing signatures and semantics. Apple-derived apps link our libnotify.so without source changes.NOTIFY_TYPE_PORT (Mach-port wakeup) — Mach IPC is the substrate, so the port-delivery type is the natural one. NOTIFY_TYPE_DISPATCH, NOTIFY_TYPE_SIGNAL, NOTIFY_TYPE_FD, NOTIFY_TYPE_CHECK all preserved as well.Provide a working libnotify + notifyd on FreeBSD so Apple-derived apps (gershwin desktop, ported Cocoa apps, third-party Apple-OSS-distributions tools) can use named pub/sub events without porting work. Replicate the API surface byte-for-byte; retain Apple's Mach-IPC substrate (libnotify ↔ notifyd via MIG over mach_msg); use POSIX shm_open(2)+mmap(2) for the shared state-value pages (the one Mach-specific mechanism with no clean equivalent on FreeBSD's Mach port — same end result, portable substrate). Preserve the performance characteristic that reads of state values are zero-IPC — that's what makes notifyd fundamentally different from a sockets-only pub/sub system.
notify_probes.d is dropped. FreeBSD has DTrace but the probe definitions are Apple-specific.notify.conf.iOSSimulator, notify.conf.iPhone dropped on import.com.apple.notifyd.sb is sandbox(7); FreeBSD has Capsicum but the policy doesn't translate. Hardening pass later.entitlements.plist, notifyutil_entitlements.plist are macOS code-signing concerns; n/a here.Libnotify.xcodeproj, xctests/, notifyd-xctests/ dropped — Xcode-only. We rebuild a minimal test corpus on top of FreeBSD's kyua or just shell scripts.Monorepo, same as the other ports on the v2 track. notifyd source lives under src/Libnotify/ at the top of freebsd-launchd-mach:
freebsd-launchd-mach/
├── src/launchd/ launchd Apple-imported source
├── src/syslog/ Apple syslog-imported source (ASL)
├── src/libxpc/ libxpc (Mach IPC client/server)
├── src/libdispatch/ libdispatch (incl. Mach backend: MACH_RECV, MACH_SEND)
├── src/libCoreFoundation/ CoreFoundation port
├── src/Libnotify/ Apple Libnotify-imported source (this plan)
│ ├── libnotify.{c,h} the libnotify client library — API surface
│ ├── notify.h public API header
│ ├── notify_keys.h public well-known notification names
│ ├── notify_client.c client-side state management
│ ├── notify_internal.h
│ ├── notify_private.h
│ ├── notify_ipc.defs MIG IDL (current)
│ ├── notify_old_ipc.defs MIG IDL (legacy, for back-compat clients)
│ ├── table.{c,h} hash-table for token registry
│ └── notifyd/ the notifyd daemon
│ ├── notifyd.{c,h} daemon main, dispatch loop
│ ├── service.{c,h} service registration + name table
│ ├── notify_proc.c per-client process tracking
│ ├── pathwatch.{c,h} path-watch notifications via kqueue
│ └── notify.conf (MacOSX flavor; iOS variants dropped)
└── build.sh top-level: builds libnotify + notifyd alongside ASL + libxpc + libdispatch
notifyd's defining feature versus a generic pub/sub system: reads of state values are zero-IPC. Apple does this with shared-memory pages — when a process registers for a name with state, it's mapped a page containing the state's uint64_t slot. The daemon writes the slot directly when state changes; client reads are a memory load. No syscall, no IPC roundtrip.
This is why notifyd works for high-frequency state (volume level updates 60Hz, network reachability checks per HTTP request, etc.) where a sockets-roundtrip-per-read would be too slow.
FreeBSD port preserves this: replace Apple's Mach-allocated shared pages with shm_open(2) POSIX shared memory (the one place we substitute a portable POSIX primitive for a Mach VM primitive — Apple's vm_allocate+port-handoff has no clean equivalent on FreeBSD's mach.ko port, but the end-user semantic — "shared page, daemon writes, clients read with no syscall" — is identical). The daemon allocates one or more shm segments holding the state-value array; clients mmap() them read-only at registration time. Daemon writes go through atomic store intrinsics (__atomic_store_n) so torn reads aren't possible.
The daemon-client channel uses Mach ports — see notify_ipc.defs + notify_old_ipc.defs (two MIG IDLs; old + current). Both are kept on the v2 track:
com.apple.notifyd via bootstrap_check_in at startup. The MIG-generated server stubs (notify_ipc_server.c) dispatch incoming mach_msg requests to the daemon's handler functions (_notifyd_server_post, _notifyd_server_register_*, _notifyd_server_get_state, _notifyd_server_set_state, etc.). The receive-side runs on a libdispatch DISPATCH_SOURCE_TYPE_MACH_RECV source attached to the service port.libnotify.c calls the MIG-generated client stubs (notify_ipc_user.c); each stub builds a mach_msg, sends it to the service port (obtained once via bootstrap_look_up("com.apple.notifyd")), and waits on the reply port. The public notify_* API remains identical to Apple's; the MIG layer is unchanged from Apple's source.NOTIFY_TYPE_PORT — daemon sends an empty mach_msg to a port the subscriber registered. Native Mach mechanism; no translation needed.NOTIFY_TYPE_DISPATCH — daemon sends a Mach message to a port driving a libdispatch source (DISPATCH_SOURCE_TYPE_MACH_RECV) in the subscriber. Same path Apple takes.NOTIFY_TYPE_SIGNAL — daemon kill(pid, sig)s the subscriber. Portable as-is.NOTIFY_TYPE_FD — daemon writes a byte to a pipe the subscriber holds the read end of. Portable as-is.notifyd implements file-path-watch notifications: subscribe to a path, get woken when the file changes. Apple's pathwatch.c uses kqueue under the hood (Darwin natively); we keep the implementation as-is. DISPATCH_SOURCE_TYPE_VNODE in libdispatch.
| Source type | Watches | Reaction |
|---|---|---|
DISPATCH_SOURCE_TYPE_MACH_RECV | notifyd's MIG service port (com.apple.notifyd, registered via bootstrap_check_in) | incoming mach_msg is dispatched through the MIG-generated server stubs (notify_ipc_server.c) to the daemon's handler functions |
DISPATCH_SOURCE_TYPE_VNODE | each registered path | fire path-changed notification to subscribers |
DISPATCH_SOURCE_TYPE_PROC | each registered client PID | auto-cancel registrations on DISPATCH_PROC_EXIT (don't deliver to dead clients) |
DISPATCH_SOURCE_TYPE_VNODE | /etc/notify.conf | reload early-access table on config change |
DISPATCH_SOURCE_TYPE_SIGNAL | SIGTERM, SIGHUP, SIGINFO | SIGTERM: clean shutdown. SIGHUP: reload conf. SIGINFO: dump stats. |
| Artifact | Path | Why |
|---|---|---|
notifyd binary | /usr/libexec/notifyd | Daemon not invoked directly. Same tier as /usr/libexec/getty, /usr/libexec/netconfigd. |
notifyutil CLI | /usr/bin/notifyutil | Admin/dev tool: post a name, watch for posts, set/get state. Standard /usr/bin for user-callable commands. |
libnotify.so | /System/Library/Libraries/libnotify.so | The client library. Apps link against this. |
| Public headers | /System/Library/Headers/notify.h/System/Library/Headers/notify_keys.h | Apps include via #include <notify.h>. |
| Mach service | com.apple.notifyd | Per-host daemon connection. notifyd checks in via bootstrap_check_in("com.apple.notifyd"); clients look up via bootstrap_look_up. launchd publishes the service via MachServices in the daemon's plist. |
| State-page directory | /var/run/notifyd/ | Daemon-managed POSIX shm names. Created by daemon at startup. |
| Config | /etc/notify.conf | Apple's "early-access" table — names that get a state slot allocated at daemon startup so they're available before the publisher posts. |
| launchd plist | /System/Library/LaunchDaemons/com.apple.notifyd.plist | Project-shipped daemon plist. Uses Apple's canonical label so apps registering for system events match Apple's bootstrap naming. |
| Decision | Choice |
|---|---|
| Source baseline | Apple Libnotify-98.5. APSL. Latest tag. |
| Mach IPC | Retained. Both .defs files (notify_ipc.defs, notify_old_ipc.defs) kept; MIG client + server stubs compiled in-tree. Service name com.apple.notifyd published via launchd's MachServices dict. |
| Shared-memory state pages | POSIX shm_open(2) + mmap(2) substituted for Apple's vm_allocate+port-handoff. Atomic updates via <stdatomic.h>. (Same end-user semantic; one Mach VM primitive without a clean FreeBSD-mach.ko equivalent.) |
| Notification delivery types | All four preserved: NOTIFY_TYPE_PORT (Mach), NOTIFY_TYPE_DISPATCH, NOTIFY_TYPE_SIGNAL, NOTIFY_TYPE_FD, NOTIFY_TYPE_CHECK. |
| Public API stability | All notify_* functions in notify.h keep their signatures and observable semantics. Source compatibility with Apple-derived apps is mandatory. |
| Event loop | libdispatch dispatch sources, incl. DISPATCH_SOURCE_TYPE_MACH_RECV (Mach backend on FreeBSD — see the libxpc libdispatch-mach spike for the enabling work). |
| Path-watch impl | kqueue (already what Apple does on Darwin; preserved). |
| License (top-level) | BSD-2-Clause. Apple's libnotify files retain APSL per-file (mix of 1.1 and 2.0 — preserve whichever the file header carries). |
src/Libnotify/)Imported source: Apple Libnotify-98.5. 48 files, ~17k LOC. 12 Mach-tied (retained); 2 MIG .defs (retained).
Libnotify.xcodeproj/, xcodeconfig/, xcodescripts/, notifyd/xcodescripts/ — Xcode build infranotifyd/com.apple.notifyd.sb — sandbox(7) profile; not portablenotifyd/entitlements.plist, notifyutil/notifyutil_entitlements.plist — code-signing entitlements; not portablenotifyd/notify.conf.iPhone, notifyd/notify.conf.iOSSimulator — iOS variantsnotify_probes.d — DTrace probe definitions (Apple-specific)xctests/, notifyd-xctests/ — XCTest harnessesnotify_private.modulemap, notify.modulemap — Clang module maps for Apple's framework build; not used in our pkg-config-based buildRetained (was deleted in the v1 / AF_UNIX-DO plan): notify_ipc.defs, notify_old_ipc.defs, notify_register_mach_port.3, all Mach-tied .c/.h files. The Mach plumbing is the substrate on the v2 track, not an amputation target.
| File | Apple LOC | Action | Target LOC |
|---|---|---|---|
libnotify.c | ~3.5k | Keep IPC layer mostly intact — Mach-port-allocation + MIG-stub-call paths run on FreeBSD via mach.ko + libxpc. Public notify_* API unchanged. Replace only the shared-memory mapping (Apple's vm_allocate + port handoff) with POSIX shm_open + mmap. | ~3.2k |
notify_client.c | ~2k | Keep. Per-token bookkeeping. Mach-aware; runs unchanged. | ~2k |
notify_ipc.defs, notify_old_ipc.defs | — | Keep. MIG IDL files; the FreeBSD mig(1) port generates client + server stubs from these (same as Apple's build). | — |
table.{c,h}, table.in.c | ~1.5k | Keep. Hash-table impl for token registry. Pure data structure. | ~1.5k |
notify.h, notify_keys.h, notify_internal.h, notify_private.h | ~1k | Keep. Public API + internal protocol declarations. All token types (incl. NOTIFY_TYPE_PORT) retained. | ~1k |
notifyd/notifyd.{c,h} | ~2k | Keep. Mach service-loop init runs on FreeBSD's mach.ko; bootstrap_check_in("com.apple.notifyd") + libdispatch DISPATCH_SOURCE_TYPE_MACH_RECV. Keep config-file load + signal handling. | ~2k |
notifyd/service.{c,h} | ~3k | Keep. Service registration + name table. Mach-port-based subscriber tracking runs as-is, augmented with DISPATCH_SOURCE_TYPE_PROC for PID-exit cleanup. | ~3k |
notifyd/notify_proc.c | ~1k | Keep. Per-client process management. Auto-cancel registrations on PROC_EXIT. | ~1k |
notifyd/pathwatch.{c,h} | ~600 | Keep mostly intact. kqueue-based; portable. | ~600 |
notifyutil/notifyutil.c | ~700 | Port. The CLI is mostly libnotify-call-and-print; once libnotify works the CLI follows. | ~700 |
notifybench/ | ~500 | Port. Useful for verifying state-page reads stay zero-IPC after our shm_open swap. | ~500 |
Manpages (notify*.3, notifyd.8, notifyutil.1) | — | Keep intact, incl. notify_register_mach_port.3. | same |
Total post-port: roughly 16-17k LOC, ~Apple's pre-port size. On the v2 (Mach-IPC) track we keep nearly all of Apple's source unchanged; only the Mach-VM shared-page handoff is substituted with POSIX shm. Compare: the abandoned v1 (AF_UNIX/DO) plan would have rewritten ~30% of the source to swap the wire layer.
| Feature | Apple's notifyd does | This port (freebsd-launchd-mach) |
|---|---|---|
| Daemon-client IPC | Mach ports + MIG-generated stubs (two flavors: current + legacy) | Identical: Mach ports + MIG-generated stubs (both notify_ipc.defs + notify_old_ipc.defs retained, generated via FreeBSD's mig(1)). Substrate provided by mach.ko + libxpc + libdispatch's Mach backend. |
| State-value pages | Mach vm_allocate + port handoff for shared memory | POSIX shm_open(2) + mmap(2). The one substitution. Same zero-IPC-read characteristic; portable across any Unix; matches Apple's user-visible semantic. |
Subscriber wakeup (NOTIFY_TYPE_PORT) | Mach mach_msg to registered port | Identical. Native Mach mechanism on the v2 substrate. |
Subscriber wakeup (NOTIFY_TYPE_DISPATCH) | Mach port message → libdispatch source | Identical. Subscriber holds a libdispatch DISPATCH_SOURCE_TYPE_MACH_RECV source; daemon sends a Mach message. |
| Path notifications | kqueue under the hood (already!) | kqueue. Identical. |
| Subscriber bookkeeping | Mach send-rights tracked per-client; subscriber-died detected via Mach port-no-senders notification | Both retained: Mach port-no-senders notification on the v2 substrate (the natural mechanism), augmented with DISPATCH_SOURCE_TYPE_PROC on each subscriber's PID as a belt-and-suspenders catch for clients that crash mid-message. |
| Build-system gates | iOS / sim / catalyst #if | Delete. One target. |
What we get when notifyd lands and gershwin's apps can use it:
| Concern | Notification name | Effect |
|---|---|---|
| Theme / appearance change | org.freebsd.appearance.theme-changed | Appearance prefs panel writes the new theme; posts the name. Every running app subscribed re-themes instantly. No per-app D-Bus connection or polling. |
| Application activation / focus | org.freebsd.workspace.app-activated | Other apps de-emphasize selves (dim accent colors, pause animations). |
| Hide / show all (NeXTSTEP signature) | org.freebsd.workspace.hide-others | Workspace single-post; all subscribed apps minimize. |
| Display configuration changed | org.freebsd.display.changed | configd or kmodloader detects framebuffer plug; posts. Workspace reflows windows; full-screen video apps react. |
| Login / logout | org.freebsd.session.user-logged-in / ...logged-out | Per-user launchd agents (mail-checker, dock helpers, calendar-sync) wake. Mirrors Apple's loginwindow flow. |
| Concern | Notification name | Effect |
|---|---|---|
| Battery / power | org.freebsd.power.battery-changed | One powermon daemon (or extension to configd's KernelEventMonitor) reads ACPI; posts current state. Workspace menubar battery icon, lid-close handler, screen-dim policy all subscribe. One source, many subscribers — without notifyd, every consumer would need its own ACPI listener. |
| Network state | org.freebsd.config.network-reachable | configd posts when an interface becomes reachable. Mail, browsers, sync clients subscribe. Apps check on each post — no polling, no per-app socket to configd. |
| Sleep / wake | org.freebsd.power.sleep-requested + ...wake | Apps save state, pause downloads, dim UI before sleep; resume after wake. |
| Time / TZ change | org.freebsd.time.timezone-changed | Calendar, Mail, Clock all subscribe. Currently apps poll or recompute on every operation. |
| Filesystem mount / unmount | org.freebsd.fs.mounted / ...unmounted | Workspace's File Viewer (Finder-equivalent) updates the sidebar. ZFS pool import — mount-aware apps refresh. |
| Keyboard layout change | org.freebsd.input.layout-changed | Apps refresh shortcut displays. |
| Audio volume / mute | org.freebsd.audio.volume-changed | Sound prefs slider follows hardware media keys; menubar volume icon updates. |
This is where notifyd shines compared to alternatives. NSUserDefaults cross-app coordination on macOS is a notifyd story:
[defaults setObject:newValue forKey:@"FontFamily"]cfprefsd-equivalent (the prefs daemon) writes the file, posts org.freebsd.prefs.<domain>.changedWithout notifyd, every app would either poll the prefs file or rely on filesystem-watching primitives like kqueue(EVFILT_VNODE) — clunky compared to a single named post. gershwin's NSUserDefaults gets a noticeable UX upgrade when this works correctly across processes.
Apple uses notifyd to trigger launchd jobs without explicit RPC:
<key>LaunchEvents</key>
<dict>
<key>com.apple.notifyd.matching</key>
<dict>
<key>org.freebsd.network-reachable</key>
<dict/>
</dict>
</dict>
A daemon plist with this LaunchEvents stanza launches its program only when that named notification posts. Auto-update checker idle until network up; backup daemon idle until specific conditions; etc. Replaces both "phase markers" (the proposed RequiresPhase per launchd plan §11.3) and ad-hoc polling with one unified mechanism. Adding LaunchEvents support to launchd alongside this notifyd port unlocks an Apple-native event-driven supervision model.
Practical concrete: any app you'd port from macOS that calls notify_register_dispatch() or notify_post() works without modification. Without notifyd we'd either need to:
With notifyd present, the calls Just Work.
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>Label</key> <string>com.apple.notifyd</string>
<key>ProgramArguments</key> <array><string>/usr/libexec/notifyd</string></array>
<key>RunAtLoad</key> <true/>
<key>KeepAlive</key> <true/>
<key>MachServices</key> <dict>
<key>com.apple.notifyd</key> <true/>
<key>com.apple.system.notification_center</key> <true/>
</dict>
</dict>
</plist>
launchd registers the Mach service names on notifyd's behalf; clients bootstrap_look_up them and obtain a send right; notifyd calls bootstrap_check_in at startup to receive the receive right. Pending client messages queue on the port even when notifyd is restarting.
notifyd has no dependencies on other daemons — it's a leaf service. ASL's libsystem_asl uses notifyd internally for fan-out (every log write posts com.apple.system.logger); configd, PowerManagement, IPConfiguration, DiskArbitration, IOKitUser all post / register for named events. Order it alongside other system daemons; no explicit ordering needed (launchd's bootstrap machinery handles "client looks up service before service has checked in" via held messages).
Apple's Libnotify source is APSL (1.1 in older files, 2.0 in newer; preserve whichever each file carries). Same family of license as ASL; FSF-approved free software; not GPL-compatible (irrelevant for our project — no GPL deps).
| Source | License | How we handle it |
|---|---|---|
| Apple Libnotify-98.5 (per-file APSL headers) | APSL 1.1 / 2.0 mix | Keep per-file headers verbatim. Our edits inherit APSL via inbound=outbound — those individual files stay APSL regardless of top-level repo license. |
| This repo's new code (FreeBSD shims, build glue, shm-replacement of vm_allocate) | BSD-2-Clause | SPDX header on each new file. |
libdispatch, libxpc, libCoreFoundation (in-tree, in src/) | Apache 2.0 / APSL | Listed in NOTICE. Same calculus as launchd/configd/ASL. |
On the v2 (Mach-IPC) track notifyd ships as part of the ASL block — see the ASL plan's Phase J1/J2 for the joint build. Reproduced here for completeness:
libnotify SHIPPEDLibnotify-98.5 into src/Libnotify/.libnotify.so: client API library. MIG client stubs generated from notify_ipc.defs via FreeBSD's mig(1). notify_post, notify_register_dispatch, notify_register_signal, notify_register_file_descriptor, notify_register_mach_port, notify_cancel all linkable; calls land on a Mach service name (no daemon yet — stubs return success).libsystem_asl because every asl_* log write posts com.apple.system.logger via libnotify.build.sh; downstream linkers see -lnotify.notifyd daemon SHIPPEDnotifyd from src/Libnotify/notifyd/. MIG server stubs generated from notify_ipc.defs.com.apple.notifyd via bootstrap_check_in; receives requests via libdispatch DISPATCH_SOURCE_TYPE_MACH_RECV on the service port.shm_open + mmap for state-value pages — atomic stores via <stdatomic.h>; clients map read-only at registration. The one substitution for Apple's vm_allocate+port-handoff.NOTIFY_TYPE_PORT, NOTIFY_TYPE_DISPATCH, NOTIFY_TYPE_SIGNAL, NOTIFY_TYPE_FD, NOTIFY_TYPE_CHECK.com.apple.notifyd.plist in /System/Library/LaunchDaemons/; launchd boot-starts it.LaunchEvents + com.apple.notifyd.matching stanza support (notifyd-driven job-on-event activation). Replaces ad-hoc polling for "wait for network up", "wait for filesystems mounted", etc.com.apple.system.config.network_change on reachability/store updates (consumed by Mail / browsers / sync clients).-lnotify and use the API natively (no porting work — Apple's code Just Works on the v2 Mach substrate).atomic_store_explicit(memory_order_relaxed) is the right primitive but compiler / target-arch-specific. Phase 2 testing covers.
NSDistributedNotificationCenter, which is GNUstep's own pub/sub mechanism (separate from notifyd). Apps using NSDistributedNotificationCenter Just Work today. Apps using notify_post need our notifyd port. Both should coexist — they don't conflict; pick the API that matches the app's expectation. Long-term gershwin question: should new app code prefer one over the other? Decision deferrable.
com.apple.* for system events. We propose org.freebsd.* for our project's posts (network, power, theme, etc.) and reserve com.apple.* for app-emitted compat names. org.gershwin.* for desktop-specific events. Keep these consistent across all FreeBSD-launchd-ecosystem code.
com.apple.system.config.network_change compat. Apple-derived apps registering for that exact name will expect it to fire on network state change. Should configd post both the Apple-canon name and our org.freebsd.config.network-changed? Decision: yes, dual-post — costs nothing, retains source compat with apps that hard-coded the Apple name.
/dev/shm/ on Linux; FreeBSD uses /tmp/... or swap/... behind the scenes. Naming scheme: org.freebsd.notifyd.state.<n> for daemon-managed segments. Per-host quota for state-value count: start at 16k slots; bump if real workloads need more.
LaunchEvents-using plists can be evaluated. If notifyd is itself launched by launchd, there's a chicken-and-egg if the launchd plist using LaunchEvents is loaded before notifyd is up. Decision: notifyd's own plist has highest priority RunAtLoad, no LaunchEvents; the launchd bootstrap machinery holds client bootstrap_look_up("com.apple.notifyd") calls until notifyd has called bootstrap_check_in. Same pattern as configd / WindowServer / any other Mach-service-providing daemon.
Libnotify-98.5).man 3 notify on macOS, or developer.apple.com/.../notify.3.html.shm_open(2): man 2 shm_open.Revision 2026-05-23. Refactored from the v1 (AF_UNIX / GNUstep DO) target to the v2 (freebsd-launchd-mach / Mach-IPC) target. notifyd SHIPPED in Phase J1 (libnotify) + Phase J2 iter 1 (notifyd daemon) under src/Libnotify/; MIG client/server stubs from notify_ipc.defs, libdispatch DISPATCH_SOURCE_TYPE_MACH_RECV on the service port, POSIX shm_open+mmap the sole substitution for Apple's vm_allocate+port-handoff. NOTIFY_TYPE_PORT retained (it was dropped in the v1 plan). Companion ASL plan at freebsd-asl-plan.html.