Skip to content

How It Works

Gil Burns edited this page Jun 7, 2026 · 2 revisions

How It Works

Third Party Patcher divides patching into four sequential phases. The patcherscheduler daemon drives all four on a configurable schedule; each phase can also be triggered manually from the command line.


The Four Phases

Scan ──► Check ──► Stage ──► Apply

1. Scan

What it does: Discovers installed third-party applications and matches them to Installomator labels.

  • Reads all label files (Installomator + Managed Labels).
  • For each label, evaluates the label's appName, targetDir, appCustomVersion, and related keys to detect whether the application is installed and what version is running.
  • Writes one .plist file per discovered app to Discovered/.
  • Respects IgnoredLabels and RequiredLabels preference filters.
  • Skips apps installed in home folders by default (IgnoreAppsInHomeFolder).

Schedule: Controlled by ScanIntervalDays (default: 30 days). Also triggered when label files are updated (ScanOnLabelUpdate: true).


2. Check

What it does: For each discovered app, looks up the latest available version.

  • Evaluates the label's appNewVersion or versionFromGit logic to determine the latest version.
  • Compares it against the installed version stored in the Discovered plist.
  • Marks apps that are behind as needing an update.
  • Respects IgnoreUnknownVersionLabels — apps where the installed version cannot be determined can be skipped.
  • Throttles repeated checks for labels that consistently report mismatched versions (VersionMismatchThrottleDays).

Schedule: Controlled by CheckIntervalHours (default: 4 hours).


3. Stage

What it does: Downloads installers for apps that need updating, validates them, and holds them ready.

  • Downloads the installer to a temporary staging area.
  • Verifies the Team ID signature against the label's expectedTeamID.
  • Only downloads each installer once until applied; re-downloads if the available version changes.
  • Respects DownloadBandwidthLimit for environments with constrained bandwidth.
  • Failed downloads are retried up to StageDownloadFailThreshold times before being skipped.

Schedule: Controlled by StageIntervalHours (default: 4 hours).


4. Apply

What it does: Runs the Installomator label to install the staged update.

  • Checks whether any blocking processes (as defined in the label) are running.
  • If a blocking process is running, prompts the user via swiftDialog (if enabled).
  • The user can quit the blocking process, defer, or (before the hard deadline) choose a custom deferral time.
  • If Focus/DND/Screen Sharing is active, the apply is silently deferred for DeferralTimerFocus minutes without prompting the user.
  • After the hard deadline, deferral is no longer available and the update is applied at the next opportunity.

Schedule: Controlled by ApplyIntervalHours (default: 24 hours), plus optional monthly patching cadence settings.


Data Flow

Label files (.sh)
       │
       ▼
   [ Scan ]  ──► Discovered/<label>.plist  (installed version, app paths)
       │
       ▼
   [ Check ] ──► Updates Discovered plist  (available version, update needed flag)
       │
       ▼
   [ Stage ] ──► Staged installer cached in temp area
       │
       ▼
   [ Apply ] ──► Installomator installs the update
                 LabelHistory/<label>.json updated

State Files

File Purpose
Discovered/<label>.plist Per-app discovered metadata (installed version, paths, update status)
Config/config.json Scheduler state (last run times for each phase, label version)
Cache/LabelHistory/<label>.json Per-label apply history (last apply date, deferral count)

Running Phases Manually

Any phase can be run on-demand from the command line:

sudo /usr/local/bin/tpp/patcher scan
sudo /usr/local/bin/tpp/patcher check
sudo /usr/local/bin/tpp/patcher stage
sudo /usr/local/bin/tpp/patcher apply

See Command-Line Reference for full options.

Clone this wiki locally