Skip to main content

CLI reference

A map of the sweetpad command-line tool: the commands you'll reach for, the global flags, the configuration files, destination specifiers, and exit codes. For a guided tour, start with Get started with the CLI or the overview.

Commands follow a resource-then-action grammar (sweetpad scheme list, sweetpad simulator boot), and the everyday actions have top-level shortcuts (sweetpad build, sweetpad test, sweetpad run). The CLI describes itself, and that is the authority: sweetpad --help lists the full command tree, sweetpad <command> --help covers the flags and subcommands this page doesn't repeat, and sweetpad help <topic> explains config, environment, exit codes, destinations, hot reload, and feedback reports.

Commands​

Everyday​

CommandWhat it does
sweetpad runThe flagship loop: build, install, launch, and follow logs. Press r to rebuild.
sweetpad buildCompile the resolved scheme. --watch rebuilds on every Swift save; --clean first cleans.
sweetpad testRun the tests. Supports --only-testing, --skip-testing, --failed, --retry-flaky, --coverage, --junit, --watch. sweetpad test build compiles them without running.
sweetpad cleanClean build artifacts; --purge also deletes DerivedData.
sweetpad archiveArchive and export an .ipa (--export-method, --output).
sweetpad formatFormat Swift sources (--check to verify only; --tool swiftlint to lint). Alias: fmt.
sweetpad devicesList everything runnable (macOS, simulators, connected devices), most-used first.
sweetpad statusShow the effective build context and where each value comes from.
sweetpad doctorDiagnose the local Xcode/Swift toolchain.

Project inspection​

CommandWhat it does
sweetpad project infoShow targets, configurations, and schemes.
sweetpad project newScaffold a minimal SwiftUI app (see options).
sweetpad scheme listList the schemes SweetPad found.
sweetpad settings showShow resolved build settings. --key NAME prints one bare value for scripts; a -- tail previews xcodebuild arguments.
sweetpad dependency listList SPM dependencies and their locked versions. Alias: dep.
sweetpad dependency addAdd a package by URL and link a product to a target.
sweetpad dependency removeRemove a package, or unlink one product from one target.
sweetpad dependency updateUpdate resolved versions, or change a requirement.
sweetpad dependency resolveResolve dependencies into the lockfile.

App lifecycle​

sweetpad run is shorthand for sweetpad app run; the rest of the lifecycle lives under app:

CommandWhat it does
sweetpad app installBuild and install without launching.
sweetpad app launchLaunch an already-installed app.
sweetpad app debugRun under lldb, attached to a suspended simulator launch, or owning the launch on macOS. --batch with --cmd drives lldb from a script.
sweetpad app diagnoseRun under lldb, catch the first crash or Objective-C exception, print a structured report, and quit. Bounded by --timeout; -o json for the machine-readable form.
sweetpad app logsFollow the running app's logs on a simulator, device, or macOS, where os_log and a detached launch's captured stdout arrive on one stream. --last <dur> prints history instead; --until <text> stops at a match; --exits lists when the app's processes ended and why.
sweetpad app stopTerminate the running app.
sweetpad app uninstallRemove the app from a simulator or device.
sweetpad app open-urlOpen a URL on a simulator, including deep links and universal links.
sweetpad app containerPrint the path of the app's data container, installed .app, or App Group containers, on a simulator or for a sandboxed macOS app.
sweetpad app screenshotSave a PNG of the running app: a macOS app's window, or the simulator it launched on.
sweetpad app sampleSample the running app for a few seconds and say whether its main thread is idle, blocked, or busy. The full report is saved too.
sweetpad app uiRead or drive a macOS app's UI through accessibility: ui tree, ui click, ui type.

Extra xcodebuild arguments​

Anything after -- goes to xcodebuild verbatim: its own flags, or KEY=VALUE build-setting overrides:

# xcodebuild flags
sweetpad app install -- -allowProvisioningUpdates
sweetpad build -- -parallelizeTargets
sweetpad archive -- -allowProvisioningUpdates

# build-setting overrides
sweetpad build -- SWIFT_ACTIVE_COMPILATION_CONDITIONS="DEBUG STAGING"
sweetpad app install --device -- DEVELOPMENT_TEAM=ABCDE12345

# both at once, and combined with SweetPad's own flags
sweetpad app install --on "iPhone 16 Pro" -- -derivedDataPath ./build ENABLE_TESTABILITY=YES

The commands that run a build accept it: build, test, archive, and app run, app install, app debug, app diagnose. The app commands that only act on an already-installed app (launch, uninstall, logs, stop) reject it rather than accept arguments that would reach no xcodebuild.

The tail can't repeat what SweetPad already passes, because xcodebuild fails on a second copy. SweetPad refuses these before it builds and names its own flag to use:

In the tailUse instead
-scheme--scheme
-configuration--configuration
-sdk--sdk
-workspace, -project--workspace, --project
-resultBundlePath--result-bundle, on test only
-archivePath, -exportPath--output-file, on archive only
-exportOptionsPlist--export-options, on archive only
-enableCodeCoveragenothing, when test has --coverage
-test-iterationsnothing, when test has --retry-flaky

The tail also can't end with a flag that still needs its value, such as a bare -xcconfig or -enableCodeCoverage. SweetPad refuses it before it builds, and it refuses a sweetpad.toml list that ends the same way.

A Swift package's tail goes to swift build or swift test instead, so none of these checks apply to it. A compiler flag you forward there can look like an xcodebuild flag, as in sweetpad build -- -Xswiftc -sdk -Xswiftc <path>.

-destination is allowed, since xcodebuild builds or tests for each one it gets. A build takes a typed -resultBundlePath in place of its own, and keeps the bundle there. xcodebuild won't write into a bundle that already exists, so remove it before the next build. Rounds of build --watch and rebuilds in a run session replace it for you.

A -derivedDataPath in the tail is honored when locating the built .app, so the bundle SweetPad installs is the one the build just wrote:

sweetpad app install -- -derivedDataPath /tmp/dd # builds and installs from /tmp/dd

A relative path is taken from the project's directory, because that's where SweetPad runs xcodebuild. For a project reached through a symlink, xcodebuild sees the directory the link points to, so ../dd lands beside the real project. app launch builds nothing and has no tail, so it takes the same location as a flag:

sweetpad build --on mac -- -derivedDataPath build/dd
sweetpad app launch --mac --derived-data-path build/dd

KEY=VALUE overrides count too, so -- PRODUCT_BUNDLE_IDENTIFIER=com.example.beta changes the bundle id SweetPad installs and launches, the same as it changes the build. So does an -xcconfig, including one that moves the product with its own SYMROOT. As in xcodebuild, a setting in the -xcconfig file wins over the same setting typed as KEY=VALUE. Hot reload recompiles with the same arguments. settings show includes the ones in sweetpad.toml and takes a -- tail of its own, so sweetpad settings show -- PRODUCT_NAME=Beta previews a one-off before you build with it.

Settings that move the product are followed the same way. -- SYMROOT=build puts the app in build/Debug-iphonesimulator beside the project, and SweetPad installs it from there. Like xcodebuild, SweetPad reads a relative SYMROOT, OBJROOT, or CONFIGURATION_BUILD_DIR against the project's directory and folds away .. and . without following symlinks. SYMROOT=../out names the out folder next to the project's folder, and settings show prints that path. Commands that don't build, such as app launch, see these settings only when they come from sweetpad.toml, so put a setting there when every command should find the moved product:

sweetpad app install -- SYMROOT=/tmp/out # builds into /tmp/out, installs from there

Writing them down for the whole repo​

An argument every build in a project needs belongs in sweetpad.toml, not in your shell history. The [xcodebuild] args list is added to every command that builds, so it reaches the builds inside app run/install/debug/diagnose as well as build, test, and archive. clean takes it too. Each command leaves out the flags its xcodebuild action refuses, so a test-only flag such as -enableCodeCoverage or -testPlan reaches test and test build and stays out of the rest. -v names each flag left out:

# sweetpad.toml (committed)
scheme = "MyApp"

[xcodebuild]
args = ["-skipMacroValidation", "-disablePackageRepositoryCache"]

A -- tail is appended after the file's arguments, so typing one wins, because xcodebuild takes the last value for a repeated flag or setting:

sweetpad build -- SWIFT_ACTIVE_COMPILATION_CONDITIONS=DEBUG # beats the file's value

Most flags that take a value, such as -xcconfig, -jobs, and -enableCodeCoverage, fail when xcodebuild gets them twice. When you type one of those after --, SweetPad leaves the file's copy out, and -v says so.

sweetpad status prints the effective list, so a build shaped by a file you didn't write still says where it came from.

Arguments SweetPad settles itself are refused in the file, naming the key to use instead: -scheme, -configuration, -destination, -sdk, -workspace, and -project. So are the paths SweetPad names itself: -resultBundlePath, which test writes and reads back, and archive's -archivePath, -exportPath, and -exportOptionsPlist. -derivedDataPath is refused too: clean --purge, derived-data, and the editor's index would keep using the DerivedData location Xcode's settings name, and a relative value would resolve against the project's directory rather than the file. Pass it per command instead. Swift packages ignore the table entirely: they build with swift build, which knows none of xcodebuild's flags.

tip

For KEY=VALUE build settings, an .xcconfig is usually the better committed home, because Xcode honors it too, so ⌘B and sweetpad build stay in agreement. Put flags in [xcodebuild] args; put build settings in an xcconfig unless you specifically want them only when building through SweetPad.

Simulators​

Alias: sim. Most take an optional target (name or UDID) and default to the booted simulator.

CommandWhat it does
sweetpad simulator listList available simulators.
sweetpad simulator bootBoot a simulator (prompts when omitted; --wait blocks until ready).
sweetpad simulator shutdownShut down a simulator.
sweetpad simulator openOpen the simulator window.
sweetpad simulator screenshotSave a PNG (--clipboard copies instead).
sweetpad simulator recordRecord the screen to an mp4. Ctrl-C stops and finalizes.
sweetpad simulator appearanceSwitch light/dark appearance.
sweetpad simulator status-barSet a clean status bar for screenshots (9:41, full bars); --clear resets.
sweetpad simulator locationSet the simulated GPS location.
sweetpad simulator pushDeliver an APNs push payload from a JSON file.
sweetpad simulator privacyGrant, revoke, or reset a privacy permission for an app.
sweetpad simulator media-addAdd photos and videos to the media library.
sweetpad simulator createCreate a new simulator.
sweetpad simulator cloneClone a shut-down simulator under a new name.
sweetpad simulator eraseErase contents and settings (simulator must be shut down).
sweetpad simulator deleteDelete a simulator. There is no undo (--yes skips the prompt).

Physical devices​

CommandWhat it does
sweetpad device listList the physical devices paired with this Mac, and whether each is on USB or Wi-Fi.
sweetpad device infoConnect to a device and report whether it's ready to build to and run on, and what to fix if it isn't. Exits 1 when it isn't ready.

Context and configuration​

CommandWhat it does
sweetpad context showShow the remembered scheme, configuration, and destination.
sweetpad context selectChange a remembered value interactively (--testing for the test context).
sweetpad context setSet a value without prompting, for scripts and CI.
sweetpad context removeClear one remembered value, or --all for the whole context.
sweetpad context aliasName a destination (context alias work-phone <UDID>), then use --on work-phone anywhere.
sweetpad open <what>Open the project in xcode, the sim window, the dd (DerivedData) folder, or your config file.

Maintenance and integration​

CommandWhat it does
sweetpad derived-data pathPrint this project's DerivedData folder (--all for the whole store). Alias: dd.
sweetpad derived-data sizeReport DerivedData's on-disk size.
sweetpad derived-data purgeDelete this project's DerivedData folder, or the whole store with --all (--yes skips the prompt).
sweetpad merge installRegister git merge drivers that resolve .pbxproj and Package.resolved conflicts semantically (--global for all repos).
sweetpad merge runResolve conflicted project files in the current merge by hand.
sweetpad bsp initWrite buildServer.json so SourceKit-LSP autocomplete works in any editor.
sweetpad bsp doctorCheck the autocomplete wiring.
sweetpad hot statusReport whether the hot-reload port is free, and which process holds it.
sweetpad hot resetEnd a hot-reload listener a dead --hot session left behind (--force for a non-sweetpad holder).
sweetpad completions <shell>Generate completions for bash, zsh, fish, elvish, or PowerShell.
sweetpad self-updateUpdate sweetpad (Homebrew installs run brew upgrade instead).
sweetpad feedback submitSend the maintainer a problem report an agent wrote, once you approve it. --dry-run prints the exact payload and a digest; --approve <digest> sends it. See Feedback reports.
sweetpad feedback offTurn feedback reports off (on turns them back on, status says which is in effect).
sweetpad help [topic]Built-in guides: config, environment, exit-codes, destinations, hot-reload, feedback.
sweetpad vscode <method>Drive a running VSCode window. See Agent CLI & RPC server.

Global flags​

These work on every command:

FlagWhat it does
-C <dir>Run as if started in that folder, like git -C.
-o, --output <mode>Output mode: human (default), json, ndjson, or quiet.
--jsonShorthand for -o json.
--non-interactiveNever prompt; missing choices become errors. Auto-enabled when CI is set.
--gh-annotationsEmit GitHub Actions annotations for build/test errors. Not combinable with -o json/ndjson.
--developer-dir <dir>Pin the Xcode to use (same as the DEVELOPER_DIR environment variable).
--no-colorDisable colored output (also honors NO_COLOR).
-v, --verboseShow raw tool output.
-q, --quietSuppress progress chatter (wins over --verbose).

-v and -q are SweetPad's own flags. To pass xcodebuild's -verbose or -quiet, put it after --, as in sweetpad build -- -quiet.

Commands that build or run also take targeting flags: --workspace, --project, --scheme, --configuration, --sdk, and the two ways to say where: --destination (a raw specifier) or --on (a human-friendly reference; the two are mutually exclusive).

Environment variables​

Every targeting flag has an environment-variable twin, so CI pipelines can set the context once: SWEETPAD_WORKSPACE, SWEETPAD_PROJECT, SWEETPAD_SCHEME, SWEETPAD_CONFIGURATION, SWEETPAD_DESTINATION, SWEETPAD_ON, and SWEETPAD_SDK. SWEETPAD_NONINTERACTIVE=1 (or CI=1) turns prompts into errors. NO_COLOR and CLICOLOR_FORCE control color. Run sweetpad help environment for the full story.

Configuration files​

Three layers, from personal to shared:

  • ~/.config/sweetpad/config.toml: your personal defaults. A [defaults] table for global values, plus [projects."<path to .xcodeproj/.xcworkspace/Package.swift>"] tables for per-project overrides. It's yours: the only thing SweetPad writes there is the [feedback] table, when you run sweetpad feedback off or on.
  • sweetpad.toml next to the project: team defaults, meant to be committed. Same keys (scheme, configuration, destination, sdk), plus developer_dir and [run], [format], [testing], and [xcodebuild] tables.
  • Remembered state: the answers you gave to interactive prompts, stored per project. Inspect and change it with sweetpad context, not by editing files.

When the same value is set in several places, the most explicit one wins:

flag > environment variable > config.toml > sweetpad.toml > remembered answer > auto-detect

Typos are never silently ignored: unknown keys produce a warning on every run. See sweetpad help config for every key.

Destinations​

--on accepts plain descriptions and resolves them against your live device list:

You writeYou get
--on "iPhone 16 Pro"The simulator or device with the closest name.
--on bootedWhatever simulator is already running.
--on macYour Mac (for macOS schemes).
--on deviceYour connected physical device.
--on ios / --on visionosThe newest simulator of that platform. watchos and tvos work too.
--on work-phoneAn alias you created with sweetpad context alias.
--on <UDID>That exact simulator or device.

--destination takes the raw, exact form instead, such as platform=iOS Simulator,name=iPhone 16 Pro or platform=macOS. That is handy in CI, where fuzzy matching would be a liability. sweetpad devices prints a copy-paste-ready specifier for everything it lists.

Exit codes and JSON output​

CodeMeaning
0Success.
1Generic failure.
2Usage error: bad flags or arguments.
3The build or the tests failed.
4Couldn't resolve a target: unknown scheme, destination, simulator…
5A required tool is missing (xcodebuild, simctl, …).
6Cancelled by you: a declined prompt, or Ctrl-C during a run's build.

With -o json, results arrive as a one-shot envelope {"schema": 1, "ok": true, "data": …}; errors go to stderr as {"schema": 1, "ok": false, "error": {"code", "message"}} where the code mirrors the exit-code taxonomy. -o ndjson streams one JSON event per line and ends with a result event, which helps for long commands like builds where you want progress as it happens.

tip

"ok": true means "the command executed", not "the outcome was good". A red test suite exits with code 3 and reports its failures inside data, so check the payload rather than the envelope.

sweetpad project new​

Scaffolds a minimal SwiftUI app. With no flags on a terminal it runs a short wizard; any flag you pass skips its question.

FlagDefaultWhat it does
--platform <ios|macos>iosTarget platform.
--bundle-id <id>com.example.<Name>Bundle identifier.
--deployment-target <ver>iOS 17.0 / macOS 14.0Minimum OS version.
--current-diroffScaffold into the current folder instead of a new one.
--no-gitoffSkip the initial git init.
--forceoffAllow scaffolding into a non-empty folder.