-
Notifications
You must be signed in to change notification settings - Fork 0
Contributing
How the repository is laid out, how to build and test it, and what a good change or bug report looks like. Read this before opening a pull request or filing an issue.
This is what is actually in the tree:
Sources/
cli/ bootstrapmate.swift — the whole command-line tool
core/
Managers/ ConfigManager, ManifestManager, IAOrchestrator, PackageManager,
ScriptManager, NetworkManager, SignatureVerifier, DialogManager,
StatusManager, ReportManager, SessionManager, CleanupManager,
TaskManager, BootstrapConfig
Utilities/ BootstrapMateConstants, Logger, ManagementDetector,
ManifestDecoder, ManifestGenerator
XPC/ HelperXPCProtocol
app/ BootstrapMateApp.swift
Services/ XPCClient
ViewModels/ SettingsViewModel
Views/ ContentView, RunView, LogView, ConsoleView, SettingsView
helper/ main.swift, HelperCommandRunner.swift
Tests/
BootstrapMateCoreTests/ BootstrapMateCoreTests.swift
packaging/
LaunchDaemons/ com.github.bootstrapmate.plist,
com.github.bootstrapmate.helper.plist
resources/ Info.plist.template
scripts/ postinstall
resources/ BootstrapMate.icon/, BootstrapMate.png, setup-notarization.sh
examples/ manifest.json, manifest.yaml, config.mobileconfig,
preflight.sh, setup-credentials.sh
Makefile
Package.swift
Package.resolved
README.md still documents an older layout with Sources/BootstrapMateCore/ and
Sources/BootstrapMateCLI/, and names files in examples/ that do not exist under those names.
Trust the tree, not the README. If you move something, fix the README in the same pull request.
Four SPM products are built from those sources: the bootstrapmate executable (target
BootstrapMateCLI), the BootstrapMateApp SwiftUI executable, the BootstrapMateHelper
privileged daemon, and the BootstrapMateCore library that the other three share. Only
BootstrapMateCore depends on a third-party package, Yams; the CLI additionally depends on
swift-argument-parser.
swift buildswift testswift build -c release --arch arm64 --arch x86_64None of that needs signing credentials. The full signed and notarized package build is a separate path — see Building and Signing.
Tests use swift-testing, not XCTest: import Testing, @Suite, @Test and #expect. There
are five suites in the single test file — BootstrapMateCore Tests, ReportManager Tests,
SignatureVerifier Tests, ManifestDecoder Tests and Logger Tests. The test target depends
on BootstrapMateCore only, so the CLI, the GUI and the helper have no test coverage; a change
in those targets is verified by building and by running it.
CI runs on every pull request against main: dependency resolution, a debug build, swift test, a universal release build, and an unsigned pkgbuild smoke test. It must be green
before a merge.
- The package is Swift 6 (
swift-tools-version:6.0) and targets macOS 15 in the manifest. - Behaviour lives in
Sources/core, not in the executables.Sources/cli/bootstrapmate.swiftparses arguments and drives the orchestrator; the GUI never installs anything itself, it asks the helper over XPC. New provisioning logic belongs in a core manager. - Managers are named
<Area>Managerand live one type per file underManagers/. Each exposes anonisolated(unsafe) public static let sharedsingleton that callers use rather than constructing an instance. - Paths, identifiers and defaults are centralised in
BootstrapMateConstants. Do not hardcode a path in a manager. - All output goes through
Loggerso that it is timestamped, levelled and written to the run log. See Logging and Reporting. - The manifest models are plain
Codablestructs with noCodingKeys. The Swift property name is the wire format. Renaming a property silently changes the key administrators must write in their manifests, so treat any rename there as a breaking change and update Manifest Reference and the files inexamples/with it. - Adding a preference key means touching
ConfigManagerfor the read, and then actually threading the value to the code that uses it. Several keys are read into the config today and never consumed; do not add another one. Preferences marks which those are.
Work on a branch and open a pull request against main; the history is merged pull requests,
with branches named for the change, such as fix/userland-resilience. Direct pushes to main
are not the norm.
Keep a pull request to one change. The commit subject is a plain, present-tense sentence saying what the change does, for example "Run userland regardless of setupassistant item failures" — no bracketed tags, no type prefixes on new commits.
If you are working on several things at once, the repository's convention is git worktrees
placed inside the repository at ./.worktrees/<name>, not as sibling directories.
Releases are cut by pushing a v<version> tag; see Release Notes for the
scheme. Do not tag as part of a feature pull request.
Provisioning failures are almost always diagnosable from the run log, so include it. A good report has:
-
The installed version, read from the bundle rather than from
--version, which reports the current time rather than the build:defaults read /Applications/Utilities/BootstrapMate.app/Contents/Info CFBundleShortVersionString -
The macOS version and architecture of the affected Mac, and whether the run happened during Setup Assistant, after login, or was started by hand.
-
The relevant part of the run log from
/Library/Managed Bootstrap/logs/. One file is written per run; take the one matching the failed run, and include the whole section around the failure rather than a single line — the line before an error usually says which item was being processed. Logging and Reporting explains the format and which greps answer which question. -
/Library/Managed Bootstrap/status.json, which records the stage, exit code and last error per phase. -
/tmp/bootstrapmate-postinstall.logif the problem is that nothing ran at all — that is where the package install and thelaunchctlload leave their evidence. -
The manifest item that failed, with its
type,file,urlandhashfields, and the exact flags or managed-preference keys in effect.
Redact before you post. Issues on this repository are public: replace internal hostnames and
manifest URLs with https://example.com/ equivalents, and remove serial numbers, user names
and Team IDs. The log's structure is what matters, not the values.
Check Troubleshooting and Gotchas first. Several behaviours that look like bugs are known and documented there, including preference keys that are read but never acted on, and a missing LaunchDaemon plist after a completed run.