deviceproof proves that an iOS app can build, install, and launch on each specified physical device. It is a macOS-only Node.js CLI built around Xcode's xcodebuild and xcrun devicectl.
It reports each device and stage independently as JSON, so an app that installs but cannot launch is never reported as a full success.
- macOS with Node.js 20+
- Xcode 15+ (including its command-line tools)
- Physical iOS/iPadOS devices on iOS 17+, paired/available to Xcode, unlocked when needed, and configured for development
deviceproof does not use a cloud service or send app/device data anywhere. devices and doctor only inspect local Xcode tooling. Only run performs installation or process-launch operations; add --dry-run to preview its commands without doing so.
v0.1 is available from source while npm distribution is prepared:
git clone https://github.com/kumpei17/deviceproof.git
cd deviceproof
npm ci
npm run build
node dist/cli.js devices
node dist/cli.js doctor
# The device ID is the devicectl identifier shown by `devices`.
node dist/cli.js run \
--app /absolute/path/MyApp.app \
--bundle-id com.example.myapp \
--device 01234567-89AB-CDEF-0123-456789ABCDEF \
--json deviceproof-report.jsonBuild from an Xcode project or workspace, then install and launch on every chosen device:
node dist/cli.js run \
--project MyApp.xcodeproj --scheme MyApp \
--bundle-id com.example.myapp \
--device DEVICE_ID_ONE --device DEVICE_ID_TWO \
--configuration Debug --allow-build --json deviceproof-report.jsonUse --workspace MyApp.xcworkspace instead of --project for workspace-based apps. Project/workspace builds use generic/platform=iOS; signing, entitlements, and device trust remain Xcode/device responsibilities.
Only use --project or --workspace for a project you trust. xcodebuild runs that project's build-phase scripts with your macOS user permissions, so deviceproof requires an explicit --allow-build acknowledgement for either option. Installing and launching a prebuilt --app does not require --allow-build.
After a project/workspace build, deviceproof installs only the exact expected device artifact: <derived-data>/Build/Products/<configuration>-iphoneos/<scheme>.app. It never scans DerivedData for a similarly named or simulator app; if that exact artifact is missing, it reports failure and does not install.
JSON reports can contain UDIDs, local device inventory details, and command output (including build stderr). Treat them as private build artifacts: do not commit them or publish them in issues, logs, or release assets. Use --redact when you need to share a report; it removes stdout/stderr and replaces device identifiers, including identifiers embedded in commands, with [REDACTED].
| Command | Purpose |
|---|---|
devices [--json path] [--redact] |
Reads the local devicectl device inventory. |
doctor [--json path] [--redact] |
Checks xcodebuild, devicectl, and local device discovery. |
run ... [--dry-run] [--json path] [--redact] |
Builds when requested, then installs and launches per device. |
run requires --bundle-id, at least one repeatable --device, and either --app or --project/--workspace with --scheme --allow-build. It exits 0 on a successful run (and dry-run), 1 when a reported operation fails, and 2 for invalid invocation. JSON records start/end timestamps, commands, exit codes, stdout, and stderr for each stage. Commands time out after 15 minutes and retain at most 1 MB of stdout and stderr per command.
This is not a replacement for UI testing, code signing, or device provisioning. It does not build per device destination; Xcode produces one generic iOS device build, while install/launch results are independently reported per actual device. A device marked available (paired) can still be usable; the definitive outcome is the reported install and launch stage.
npm install
npm test
npm run typecheck
npm run buildSee CONTRIBUTING.md for contribution guidance and SECURITY.md for vulnerability reporting.