02 Jul Building Your Own Installomator, Part 3: Hands-On, Pulling and Curating Labels

Forking, curating labels, and packaging an internal build
Part 3 of a 4-part series
Part 2 covered branches and how much process your team needs. This post is the hands-on middle of the series: how the project’s files actually fit together, and three different ways to pull, curate, and review labels depending on how comfortable you are with Git.
The Key Detail: Installomator Is Built from Fragments
Modern Installomator is not maintained as one giant hand-edited Installomator.sh file. The project is assembled from fragment files. This is documented in detail in the project’s own utils/README.md; the summary below covers what you need for curating labels.
The official repo notes that contributors should edit files in fragments/, not the generated root Installomator.sh. The full script is assembled from those fragments, and the root script can be overwritten during release work.
The simplified structure looks like this:
Installomator/
|-- assemble.sh -> utils/assemble.sh
|-- Installomator.sh
|-- Labels.txt
|-- fragments/
| |-- header.sh
| |-- version.sh
| |-- functions.sh
| |-- arguments.sh
| |-- labels/
| | |-- zoom.sh
| | |-- firefox.sh
| | `-- ...
| `-- main.sh
`-- utils/
`-- assemble.sh
The assemble.sh tool combines those pieces and writes a built script to:
build/Installomator.sh
When requested, it can also copy the built script back to the repo root as Installomator.sh.
One subtle but very important point: assemble.sh --labels /path/to/custom-labels adds your custom labels before the default fragments/labels directory. That is great for testing or overriding labels. It does not, by itself, create a script containing only your custom labels. If you want a smaller script with only your selected labels, curate the fork’s fragments/labels folder or use a dedicated build branch where that folder contains only the labels you want.
Version Note as of This Post
As of this July 2026 update, Installomator v10.9 is the latest formal GitHub release. Work that will become part of a future 10.10 release can appear on main before a new packaged release is cut. This is exactly why it is useful to distinguish between a GitHub release, the main branch, and your own assembled internal build.
The version numbers can be a little confusing because the repo has more than one useful state:
Upstream GitHub release/tag -> v10.9, as of this July 2026 update Upstream release branch -> latest formal release line Upstream main branch -> beta / next-release work, including newer merged labels headed for 10.10 or later Your internal build -> whatever commit, branch, or tag you assemble and deploy
For a curated fork, the important takeaway is that the version printed by the script tells you which upstream Installomator code line you started from, but it does not fully describe your internal label set. If you build from v10.9 and remove most labels, you still have an internal build based on v10.9, not the same artifact as the public v10.9 package. If you build from main after v10.9 to pull in newer merged label fixes, you may have labels or fixes that are likely headed for 10.10 or a later release even though no newer packaged release exists yet.
That is why I like tagging internal builds separately, for example:
internal-installomator-10.9-2026.07.07 internal-installomator-main-2026.07.07
Those tags make the relationship clear: which upstream release or branch you started from, plus the date of your reviewed internal build.
Workflow 1: GitHub Web Interface
This is the friendliest path if you are not living in Terminal all day.
- Open the Installomator repository:
https://github.com/Installomator/Installomator
-
Click Fork.
-
Choose your user or organization as the owner.
-
Leave the name as
Installomator, or rename it to something explicit like:
installomator-internal
-
Clone your fork later using GitHub Desktop or the command line.
-
Create a production branch in GitHub:
production
- In that branch, open:
fragments/labels/
-
Delete labels you do not want in your internal build.
-
Add or edit internal label files as needed.
-
Commit the changes.
-
Pull the repo locally and run:
./assemble.sh --script
That will assemble the curated version into the root Installomator.sh.
Pulling in a label from upstream using the web UI
When upstream adds or fixes a label you want:
- Open the upstream Installomator repo.
- Navigate to
fragments/labels/. - Open the label file you want.
- Copy the label content.
- Open your fork and switch to your production or testing branch.
- Create or edit the matching file in
fragments/labels/. - Commit the change with a clear message:
Update zoom label from upstream Installomator
This is manual, but it is understandable and reviewable.
Workflow 2: GitHub Desktop on macOS
GitHub Desktop is a nice middle ground: you get branches, diffs, commits, and sync without needing to memorize Git commands.
-
Fork Installomator on GitHub.com.
-
Open GitHub Desktop.
-
Choose:
File > Clone Repository
-
Select your fork.
-
Clone it somewhere predictable, for example:
~/Developer/installomator-internal
- Create a branch:
production
- In Finder or your editor, open:
~/Developer/installomator-internal/fragments/labels/
-
Remove the label files you do not want in your internal build.
-
Add your local label files.
-
Review the diff in GitHub Desktop.
-
Commit:
Curate production label set
-
Publish or push the branch.
-
Open Terminal from the repo folder and build:
./assemble.sh --script
GitHub Desktop handles the Git work; Terminal handles the build.
Updating from upstream in GitHub Desktop
There are two common approaches.
The simple approach is to use GitHub’s Sync fork button on the website, then pull the changes in GitHub Desktop.
The more controlled approach is to maintain a separate upstream-tracking branch and selectively copy labels into your production branch. That keeps new upstream labels from automatically appearing in your internal production build.
For a curated Installomator, I prefer controlled copying. A small amount of manual work is a feature here, not a bug.
Workflow 3: Git Command Line
This is the most repeatable path and the easiest to automate later.
First, fork the repo on GitHub. Then clone your fork:
cd ~/Developer git clone git@github.com:YOUR-ORG/installomator-internal.git cd installomator-internal
Add the official Installomator repo as upstream:
git remote add upstream https://github.com/Installomator/Installomator.git git remote -v
You should see something like:
origin git@github.com:YOUR-ORG/installomator-internal.git (fetch) origin git@github.com:YOUR-ORG/installomator-internal.git (push) upstream https://github.com/Installomator/Installomator.git (fetch) upstream https://github.com/Installomator/Installomator.git (push)
Fetch upstream:
git fetch upstream
Create your production branch:
git switch -c production
Curate your labels:
cd fragments/labels
Remove labels you do not want, or move them into an archive outside the active labels folder:
mkdir -p ../../archived-labels git mv unwantedlabel.sh ../../archived-labels/
Add your local labels:
cp ~/Documents/internal-installomator-labels/*.sh .
Commit:
git add fragments/labels archived-labels git commit -m "Curate production Installomator labels"
Build:
cd ../.. ./assemble.sh --script
Test a label in debug mode:
./assemble.sh zoom
Test an actual install only when ready:
sudo ./assemble.sh zoom NOTIFY=silent DEBUG=0
Building a Script with Only the Labels You Want
If your goal is a smaller Installomator.sh, do not rely only on:
./assemble.sh --labels ~/Documents/MyLabels --script
That command adds your labels before the default labels. It is ideal for overrides and local testing, but the default labels still come along for the ride.
For a truly curated build, use one of these patterns.
Pattern A: Curate fragments/labels in Your Production Branch
This is the simplest and most visible.
production
`-- fragments/labels/
|-- firefox.sh
|-- googlechrome.sh
|-- microsoftoffice365.sh
|-- slack.sh
`-- zoom.sh
Then build:
./assemble.sh --script
Pattern B: Keep Upstream Labels in One Branch, Production Labels in Another
Use main to track upstream and production for your reduced label set.
When you want a newer upstream label:
git fetch upstream git switch production git checkout upstream/main -- fragments/labels/zoom.sh git commit -m "Update zoom label from upstream" ./assemble.sh --script
That pulls in one label, not the entire upstream label catalog.
Pattern C: Maintain an Internal Labels Folder for Overrides
This works well when you mostly use upstream labels but need local overrides:
./assemble.sh --labels ~/Documents/InstallomatorLabels zoom
Because custom label locations are inserted before the default labels, a custom zoom.sh can override the upstream zoom.sh.
This is not the best method for building a tiny script, but it is excellent for testing and overriding.
Example: Pulling in One Upstream Label
Say your internal production build does not currently include pgadmin4, but you decide you want it.
From your fork:
git fetch upstream git switch production git checkout upstream/main -- fragments/labels/pgadmin4.sh git diff -- fragments/labels/pgadmin4.sh git commit -m "Add pgAdmin 4 Installomator label" ./assemble.sh --script
Then test:
./assemble.sh pgadmin4
When satisfied:
sudo ./assemble.sh pgadmin4 NOTIFY=silent DEBUG=0
Example: Keeping a Local Override
Suppose upstream has a label you like, but your environment needs a different download source or a different blockingProcesses value.
Copy the upstream label into your production branch:
git checkout upstream/main -- fragments/labels/exampleapp.sh
Edit it locally:
code fragments/labels/exampleapp.sh
Commit the local policy decision:
git add fragments/labels/exampleapp.sh git commit -m "Customize exampleapp label for internal deployment"
Later, when upstream changes that label, do not blindly overwrite your version. Compare first:
git fetch upstream git diff HEAD..upstream/main -- fragments/labels/exampleapp.sh
Then decide whether to merge, copy, or ignore the upstream change.
Suggested Review Checklist for Labels
Before a label goes into your production branch, check:
- Is the label using the vendor’s official source, or a clearly justified fallback such as a GitHub release, Sparkle feed, official API, Homebrew Cask, or AutoPkg recipe?
- Does
downloadURLresolve to the expected vendor artifact, including after redirects? - Are
downloadURLandappNewVersionderived from the same trusted source when possible, so the version and installer cannot drift apart? - Does
appNewVersionreturn a non-empty value that matches the downloaded app or package version format? - Is the artifact type correct:
dmg,pkg,zip,tbz, or another Installomator-supported type? - Have you inspected the downloaded payload, not just the web page, to confirm the app name, package contents, or nested folder structure?
- Does
expectedTeamIDmatch the signed app or package from the downloaded artifact? - Does the label need architecture logic for Apple Silicon vs Intel?
- Does the installed app bundle match
name, or do you needappNamefor cases likename="Snagit"andappName="Snagit 2024.app"? - Does
versionKeyneed to be set because the app reports the useful version inCFBundleVersioninstead ofCFBundleShortVersionString? - For DMGs or ZIPs with an enclosing folder, do you need
folderName, and have you confirmed Installomator will copy the required folder structure? - Are
blockingProcessescorrect and not overly broad? - Are helper variables useful, or can the label be made smaller without making it harder to review?
- Is the parsing reasonably stable, preferring JSON, XML, Sparkle appcasts, GitHub release data, or other structured sources over broad HTML scraping?
- Has the label been tested with
DEBUG=1first? - Has the install been tested on a sacrificial Mac or VM before production?
Next in this series: Part 4 covers turning your curated build into something deployable — a release flow, deploying the built script directly to Jamf Pro, and packaging a signed or unsigned installer with munkipkg.
No Comments