01 Jul Building Your Own Installomator, Part 1: Why Fork It, and a Quick Start
Forking, curating labels, and packaging an internal build
Part 1 of a 4-part Series
This is the first of four posts on maintaining your own internal fork of Installomator: forking, curating labels, and packaging a build for your MDM. This one covers what problem forking actually solves and gets you a working package fast if you just want to try it. Later posts cover branch strategy, hands-on label curation, and packaging in more depth.
Installomator is an open-source macOS deployment script used to install and update common Mac applications directly from vendor download sources. Instead of downloading a package, uploading it to your MDM, maintaining a static installer, and replacing that package every time the vendor ships an update, an admin calls Installomator with a label, such as zoom, googlechrome, or slack. That label tells Installomator where to find the current installer and how to validate it.
From there, Installomator handles the repetitive deployment work: checking the installed version, determining the latest available version, downloading the correct payload, validating the Apple Developer Team ID, handling common installer formats such as DMG, PKG, and ZIP, installing the app, respecting blocking process behavior, and cleaning up temporary files. In Jamf Pro or another MDM, this means a policy can often be reduced to “run Installomator with this label and these options” rather than “host and maintain a separate installer package for this app.”
The power of Installomator is in its label library. Each label contains the app-specific logic: where to download the installer, how to determine the latest version, what installer type to expect, and which Apple Developer Team ID should sign the payload. That makes Installomator flexible, but it also means the label set becomes part of your deployment trust chain.
Installomator is one of those Mac admin tools that starts simple: run a label, install the app, move on with your day. Then your environment grows. You add more titles, more exceptions, more review requirements, and suddenly you are thinking less about “Can Installomator install this?” and more about “Which version of Installomator do I want my Macs to trust?”
That is where maintaining your own fork starts to make sense.
The release cadence matters here. The project can have label fixes and additions merged to `main` well before they are included in the next formal release package. For example, the label work that will become part of a future `10.9` release may already be present on `main` while the latest formal release is still older. If you are only pulling packaged releases, you can be behind on label fixes even when the repo itself is active.
To put a number on it: as of mid-2026, the last signed package release from the project was cut on March 28, 2025. Since then, over 1,100 commits have landed on the main branch without a corresponding official package build — the large majority of them label fixes and additions, alongside the usual mix of doc and workflow tweaks. If you are only pulling packaged releases, you are sitting more than a year behind on label fixes, not just missing a handful of edge cases.
This post walks through a practical workflow for forking Installomator, building your own version, pulling in upstream label updates when you want them, and building your own installer package for your internal deployment. The closest official guidance is in the Installomator repo itself, especially the utils/README.md and comments around assemble.sh.
Quick Start: Just Build Me a Package
If you do not have time for the rest of this post, here is the minimum path to a working, signable-or-not .pkg that installs Installomator to /usr/local/Installomator/Installomator.sh. This skips forking, curation, and review; it is meant to get you a package today. Read the rest of the post before you rely on this for production.
First, download a copy of Installomator:
# 1. Get Installomator git clone https://github.com/Installomator/Installomator.git cd Installomator
Now decide which version you want. Pick one:
- The newest labels, including fixes that may be headed for the next release, such as 10.9 (recommended for this quick start), do nothing else. The command above already gives you this.
- The last official, fully tested release instead: run one more command:
git checkout release
If you are not sure which to pick, the newest-labels option above is fine for testing. Just test the specific apps you plan to deploy before rolling out to real Macs.
# 2. Build the full script from the current fragments ./assemble.sh --script # 3. Get munkipkg cd .. git clone https://github.com/munki/munki-pkg.git ln -s "$(pwd)/munki-pkg/munkipkg" /usr/local/bin/munkipkg # 4. Set up a package project mkdir -p installomator-pkg/payload/usr/local/Installomator mkdir -p installomator-pkg/scripts cp Installomator/Installomator.sh installomator-pkg/payload/usr/local/Installomator/Installomator.sh chmod 755 installomator-pkg/payload/usr/local/Installomator/Installomator.sh
Do not skip the ./assemble.sh --script step just because the repo already contains a root Installomator.sh file. That file may be recent, but it is still a generated artifact. Labels can land in fragments/labels/ after the root script was last rebuilt, so assembling locally is the way to make sure your script actually contains the current fragments from the branch you chose.
Create installomator-pkg/build-info.plist with your own identifier and version:
<?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>distribution_style</key>
<false/>
<key>identifier</key>
<string>edu.example.installomator</string>
<key>install_location</key>
<string>/</string>
<key>name</key>
<string>Installomator-${version}.pkg</string>
<key>ownership</key>
<string>recommended</string>
<key>postinstall_action</key>
<string>none</string>
<key>suppress_bundle_relocation</key>
<true/>
<key>version</key>
<string>2026.07.01</string>
</dict>
</plist>
Replace edu.example.installomator with a reverse-DNS identifier you actually control, and set version to whatever date-based or numeric scheme you want to track. Then build:
munkipkg installomator-pkg
The finished package lands in installomator-pkg/build/. Install it on a test Mac and confirm it before pushing it anywhere near production:
sudo installer -pkg installomator-pkg/build/Installomator-2026.07.01.pkg -target / /usr/local/Installomator/Installomator.sh version sudo /usr/local/Installomator/Installomator.sh zoom DEBUG=1
Two things this quick path deliberately skips, both covered later in this series: it pulls straight from main, meaning newer labels but no formal upstream release testing behind them, and it does not sign or notarize the package, which is fine for internal deployment through Jamf Pro or another MDM but matters if you plan to distribute it any other way. It also does not use the official assemble.sh --pkg flag, since that flag is hardcoded to the project maintainer’s own package identity and signing certificate rather than yours. More on that next.
If you want a curated, reviewed, or repeatable version of this instead of a one-off, keep reading.
Why Not Just Run assemble.sh --pkg?
This is the first tempting shortcut, and it is worth being very clear about it: assemble.sh --pkg is useful if you are building the upstream Installomator release package with the upstream release identity. It is not a general-purpose “make my organization’s Installomator installer” command.
The reason is in the packaging variables near the top of utils/assemble.sh. In the upstream project, they are set for the maintainer’s package identity:
pkgname="Installomator"
identifier="com.scriptingosx.${pkgname}"
install_location="/usr/local/Installomator/"
signature="Developer ID Installer: Armin Briegel (JME5BW3F3R)"
Later, the --pkg path uses those values directly with pkgbuild and productbuild. That means the package identifier, install location, package name, version, and signing identity all come from the upstream script defaults unless you edit the build script itself.
On your Mac, one of three things will happen:
- If you do not have that exact Developer ID Installer certificate,
productbuild --signfails. - If you remove signing or edit the signing line casually, you now have a local modification to the upstream build tooling that you need to remember, preserve, and reapply.
- If you change the hardcoded values in
assemble.sh, you have turned the upstream release helper into your private packaging script, which makes future upstream merges noisier than they need to be.
That is why I prefer building the script with:
./assemble.sh --script
Then package the assembled Installomator.sh with your own packaging project. With munkipkg, the package identity lives in your build-info.plist, where it belongs:
<key>identifier</key> <string>edu.example.installomator</string>
That separation is the whole point. Let Installomator’s assemble.sh assemble Installomator. Let your packaging project describe your organization’s installer package.
Why Fork Installomator?
You do not need to fork Installomator just to use it. If the public script works for your environment, keep using the release version and spend your time elsewhere. A fork is useful when you want a controlled internal build.
Good reasons to fork:
- You want only approved labels in your production script.
- You want the latest upstream label fixes, but only after you review and repackage them.
- You want to review label changes before they reach production.
- You maintain local-only labels that would not make sense upstream.
- You need to override a public label for your environment.
- You want an auditable Git history for every label added, removed, or changed.
- You want a repeatable build process instead of copying chunks of shell script around.
The important mental model: your fork is not “better Installomator.” It is your organization’s distribution of Installomator.
What If Your Internal Version Needs to Be Private?
One important GitHub detail: you generally cannot use GitHub’s normal Fork button to turn a public repository into a private fork. If your organization has custom labels, internal download URLs, or override logic you do not want public, create a new private repository and treat the public Installomator repo as an upstream remote.
The workflow works like this:
git clone https://github.com/Installomator/Installomator.git installomator-internal cd installomator-internal git remote rename origin upstream git remote add origin git@github.com:YOUR-ORG/installomator-internal.git git push -u origin main
From there, your private repo is the one your team works in, and upstream remains the public Installomator project you fetch label updates from:
git fetch upstream git checkout upstream/main -- fragments/labels/zoom.sh git commit -m "Update zoom label from upstream" git push origin main
That gives you the practical benefits of a fork without publishing your local labels or internal packaging work.
How Installomator Is Set Up
Installomator can be used in a few different ways, but the basic pieces are the same:
- A large shell script named
Installomator.sh - A library of app labels
- Runtime options such as
DEBUG,NOTIFY, andBLOCKING_PROCESS_ACTION - A deployment system, such as Jamf Pro, another MDM, or a local command line
This is covered in more detail in the project’s own Using Installomator wiki page; the summary below is just enough to follow the rest of this series.
The simplest use is:
sudo ./Installomator.sh zoom
That tells Installomator to run the zoom label. A more realistic Jamf Pro-style call might include options:
sudo ./Installomator.sh zoom NOTIFY=silent BLOCKING_PROCESS_ACTION=ignore DEBUG=0
In production, teams commonly deploy Installomator in one of three ways:
- Upload the full
Installomator.shas a Jamf Pro script. - Install
Installomator.shlocally with a package, then call it from small Jamf Pro or other MDM wrapper scripts. - Keep the script in a Git repo and use it directly for testing, packaging, or scripted deployment.
The project source is organized differently from the final deployed script. The generated Installomator.sh is assembled from fragment files. The app-specific label files live under:
fragments/labels/
That distinction matters. If you are maintaining your own fork, you usually edit labels in fragments/labels/, then run assemble.sh to create the final script you deploy.
Next in this series: Part 2 covers how Installomator’s branches actually work, what “beta” really means for main, and how to pick the right level of process for your team — from “just track upstream” to a fully curated internal distribution.

No Comments