
Astrolabe is a declarative macOS configuration framework. You describe the desired state of a machine in Swift — packages, services, system settings, and related setup work — and Astrolabe keeps the machine moving toward that state over time. This update adds a built-in way for the Astrolabe binary itself to update after it has been installed.
What is Astrolabe
Astrolabe is a Swift framework for describing how a Mac should be set up.
Instead of writing a script that runs commands once, you declare the packages, services, and settings that should exist. Astrolabe runs in the background and keeps checking that the machine still matches that definition.
A small setup looks like this:
Astrolabe runs as a LaunchDaemon. On each tick, it reads the current state, builds the desired setup tree, compares it with what it saw before, and runs the needed work. The goal is simple: keep Mac setup predictable without turning every machine into a one-off script.
Astrolabe binaries can now update themselves
Astrolabe now has a built-in self-update mechanism for the Astrolabe binary itself.
Before this change, Astrolabe could keep a Mac's configuration in sync, but the binary running that configuration still needed its own update path. If you shipped a new version of the Astrolabe binary, you had to get that new binary onto the machine and restart the daemon yourself.
Now a deployed Astrolabe binary can opt in to self-updates with static var update. When you install the daemon, Astrolabe also installs a sibling updater daemon for that same binary. The updater checks a release source, downloads a newer package for the binary, verifies it, installs it, and restarts the main daemon so the new binary is running.
The feature is meant for Astrolabe binaries that are already deployed to Macs. If you ship one binary to a fleet, that binary can now keep itself current instead of depending on a separate replacement path.
How to opt in
Every self-updating Astrolabe binary declares a version:
That version is used by the updater to compare the local binary with the latest available release. Versions are parsed as SemVer, so releases like 1.2.3 and 1.2.3-beta.1 work as expected.
To make the binary self-updating, add an update configuration:
The minimum version is even smaller:
By default, Astrolabe checks the stable GitHub release channel once an hour and requires the downloaded package to pass pkgutil --check-signature.
What the updater does
When install-daemon runs, Astrolabe installs the main daemon as before. If update is configured, it also installs a second LaunchDaemon for the same binary, using a hidden update loop command.
On each update tick, the updater:
Fetches the latest release from the configured source.
Compares the release version against
App.version.Skips the update if the local version is already current.
Refuses downgrades by default.
Downloads the matching
.pkgfor the newer Astrolabe binary.Verifies the package signature.
Runs any
preUpdatehook.Installs the package with
/usr/sbin/installer.Runs any
postUpdatehook.Restarts the main daemon with
launchctl kickstart.Re-execs itself so the updater also runs from the new binary.
The main point is that the binary replacement happens out of process. The main Astrolabe daemon is not trying to overwrite itself while it is doing normal setup work. The updater has its own daemon, its own loop, and its own status.
Configuration options
The update API is small, but it covers the common cases:
A few details matter:
.stabletracks the latest stable GitHub release..prereleasecan include prerelease builds..pkgSignatureRequiredrequires a valid package signature..codesignTeamID(...)also checks that the signing Team ID matches what you expect..allowDowngrade(false)is the default..githubToken(...)lets the updater access private release sources for the binary.Hooks let you run work before an update, after an update, or after a failure.
You can also pin a release tag:
That is useful for staged rollouts or a controlled rollback path. The updater installs that tag once if it is newer than the local version, then no-ops.
Checking update status
Astrolabe also adds a public command:
It prints the current binary version, whether self-update is configured, the last check time, the last seen version, the last successful update time, and the last error.
Uninstall also understands the updater now:
That removes the updater daemon first, then the main daemon.
What to keep in mind
This feature does one specific thing: it updates the Astrolabe binary that is already installed on the Mac.
It does not update every app or package on the machine. For example, Astrolabe can still install and manage tools like Homebrew packages, but this self-update feature is only for replacing the Astrolabe binary itself with a newer version.
Try it
Learn more about Photon at photon.codes, or read the Astrolabe source on GitHub.


