Skip to content

Manifest Reference

Rod Christiansen edited this page Sep 3, 2026 · 1 revision

Manifest Reference

The complete manifest schema. Key names are the Swift property names verbatim — the decoder defines no key mapping — so spelling and casing must match exactly, including the camelCase keys skipIf, followRedirects, expectedTeamID and allowUnsigned. An unrecognised key is ignored without a warning, which is what a typo looks like from the outside.

The same schema applies to JSON and YAML. See Manifests for how the format is chosen and Example Manifests for working documents.

Top-level keys

Key Type Required Default Summary
preflight Array of items No none Single root script that can short-circuit the whole run
setupassistant Array of items No none Items run as root before a user session exists
userland Array of items No none Items run after a console user logs in

preflight

  • Type: Array of items
  • Default: none
  • Required: No

The first stage. Only the first item whose type is rootscript is used; any other item in the array is ignored. Its exit code decides whether the rest of the run happens at all. An absent or empty array means the run proceeds directly to setupassistant. See Stages.

setupassistant

  • Type: Array of items
  • Default: none
  • Required: No

Items run in array order, as root, without waiting for a user session. Every item is attempted; a failure is recorded and marks the run unsuccessful, but does not abort the stage or prevent userland from running.

userland

  • Type: Array of items
  • Default: none
  • Required: No

Items run in array order, after BootstrapMate has waited for a console user to log in. Also the only stage --userscript looks at.

Item keys

Key Type Required Default Summary
file String Yes Absolute destination path on disk
hash String Yes Lowercase hex SHA-256 of the payload
url String Yes Download source
type String Yes package, rootscript or userscript
name String No value of file Display name in logs and the dialog
packageid String No none pkgutil receipt id for the already-installed check
version String No none Minimum version for the already-installed check
retries Int or String No 3 Download attempts
retrywait Int or String No 5 Seconds between download attempts
skipIf String No none Architecture on which to skip this item
followRedirects Bool No false Accepted but does not change behaviour
donotwait Bool No false Scripts only: launch and continue immediately
expectedTeamID String No config value Required signing Team ID for this package
allowUnsigned Bool No config value Permit an untrusted signature on this package

file

  • Type: String
  • Default: none
  • Required: Yes

The absolute path the payload is written to, and the path BootstrapMate then acts on: for a package it is passed to /usr/sbin/installer -pkg, and for a script it is the executable that gets run. Nothing derives the path for you, and nothing cleans it up afterwards — downloaded payloads stay on disk after the run.

The path doubles as the resume mechanism. If a file already exists at file and its SHA-256 matches hash, the download is skipped with Already have valid file: <path>. Skipping re-download. Give each item a distinct path; two items sharing one path will collide.

hash

  • Type: String
  • Default: none
  • Required: Yes

Lowercase hex SHA-256 digest of the payload, computed over the exact bytes served. It is verified after every download attempt and a mismatch is a failure, so this is the field that must be updated whenever the payload behind url changes. Produce it with shasum -a 256 <file>.

For a package the hash proves the bytes match the manifest; it does not prove the package is authentic. Signature verification does that — see Security and Package Verification.

url

  • Type: String
  • Default: none
  • Required: Yes

Where the payload is downloaded from. The configured Authorization header, if any, is sent with the request. HTTP status codes are not checked: an error page downloads "successfully" and then fails the hash check.

type

  • Type: String
  • Default: none
  • Required: Yes

One of package, rootscript, userscript. Any other value logs Unknown item type: <type> and fails the item. The values are case-sensitive. Behaviour per type is on Item Types.

name

  • Type: String
  • Default: the value of file
  • Required: No

Human-readable label used in log lines and as the row title in the SwiftDialog progress window. Set it — the fallback is a full filesystem path, which reads badly in both places.

packageid

  • Type: String
  • Default: none
  • Required: No

A pkgutil receipt identifier, for example com.googlecode.munki.core. Used only for the already-installed check on package items, and only when version is also set. On its own it does nothing.

version

  • Type: String
  • Default: none
  • Required: No

The minimum acceptable installed version, paired with packageid. When both are present BootstrapMate runs pkgutil --pkg-info-plist <packageid> and compares the receipt's pkg-version against this value; if the installed version is greater than or equal, the item is skipped as already installed and reported as a success.

The comparison splits both strings on . and compares the components as integers, padding the shorter side with zeros. Non-numeric components are dropped by that parse, so version strings that are not purely numeric dotted forms will not compare the way they read.

retries

  • Type: Int, or a String containing an integer
  • Default: 3
  • Required: No

Total number of download attempts for this item's payload, not extra attempts after the first. The hash is re-verified after each. Both 3 and "3" decode. Applies to downloads only — a failed installer or a failing script is never retried. See Retries and Timeouts.

retrywait

  • Type: Int, or a String containing an integer
  • Default: 5
  • Required: No

Seconds to sleep between download attempts. The sleep also happens after the final failed attempt, so a fully failing item costs retries × retrywait seconds of waiting on top of the transfers.

The comment block in the shipped examples/manifest.yaml says the default is 10. The code default is 5.

skipIf

  • Type: String
  • Default: none
  • Required: No

Names the architecture on which this item should be skipped. The value is lowercased and matched by substring: a value containing arm or apple_silicon skips the item on Apple silicon, and a value containing x86_64 or intel skips it on Intel. There is no other kind of condition — no OS version, model, hostname or MDM check.

skipIf also suppresses the payload download on the architecture where the item is supposed to run, so an item carrying skipIf will fail on that architecture unless the file is already present at file with a matching hash. Read Conditions and Skipping before using this key, and see Troubleshooting and Gotchas.

followRedirects

  • Type: Bool
  • Default: false
  • Required: No

Present in the schema and threaded through the download call, but the networking layer installs no redirect-controlling delegate, so redirects are followed regardless of this value. Setting it changes nothing in either direction. The same is true of the --follow-redirects flag and the followRedirects preference.

donotwait

  • Type: Bool
  • Default: false
  • Required: No

Scripts only. When true the script is launched and BootstrapMate moves on immediately without waiting for it to finish; the item is recorded as a success as soon as the process launches, and the script's own exit code is never seen. Output is not captured for these items. Has no effect on package items.

Because the bootstrap daemon plist sets AbandonProcessGroup, a donotwait child survives BootstrapMate's own teardown — which is what makes it usable for handing off to Munki.

expectedTeamID

  • Type: String
  • Default: the expectedTeamID value from configuration
  • Required: No

A ten-character Apple Team ID that this package's installer signature must carry. A mismatch always refuses the install, logging Refusing to install <pkg>: Team ID mismatch — found X, expected Y; allowUnsigned does not override it. Applies to package items only — scripts get no signature check.

allowUnsigned

  • Type: Bool
  • Default: the allowUnsigned value from configuration
  • Required: No

When true, a package whose signature is untrusted or missing is installed anyway, with the warning Package signature not trusted (<reason>) — proceeding because allowUnsigned is set. It does not bypass an expectedTeamID mismatch. Applies to package items only.

Keys that are not part of this schema

options, and its enabled / followRedirects / authorizationHeader members, belong to a separate legacy configuration shape that the runtime manifest loader never decodes. Adding an options block to a manifest has no effect. Global authentication and redirect settings come from the CLI flags and the preference domain instead — see Preferences.

See also

Clone this wiki locally