Why Not Just Use xcodebuild?

You can. We do.

FlowDeck calls xcodebuild under the hood. Same build system, same schemes, same signing. The difference is everything around it.

The Problem Isn't xcodebuild

It's that xcodebuild is just one piece.

A build needs:

  • xcodebuild to compile
  • xcrun simctl to manage simulators
  • xcrun devicectl to manage physical devices
  • xcrun simctl launch to run the app
  • xcrun simctl spawn ... log stream to see logs
  • Shell scripts to glue it together
  • Regex to parse the output

That's not a workflow. That's archaeology.

Side by Side

What You're Doing Apple's Tools FlowDeck
Target a simulator xcrun simctl list, find UDID, construct platform=iOS Simulator,name=iPhone 16,OS=18.0 -S "iPhone 16"
Target a device xcrun devicectl list, copy UDID, hope the syntax is right -D "iPhone"
Build for Mac Figure out which destination string works this year -D "My Mac"
Build and run xcodebuild, then simctl install, then simctl launch flowdeck run
Stream logs xcrun simctl spawn booted log stream --predicate 'subsystem contains...' flowdeck logs
Run one test -only-testing:MyAppTests/LoginTests/testValidLogin --only LoginTests/testValidLogin
Skip slow tests -skip-testing:MyAppTests/SlowTests --skip SlowTests
Discover tests Build first, then parse output flowdeck test discover
Find schemes xcodebuild -list (2-5 second wait) flowdeck context (instant)
Clean everything xcodebuild clean + rm -rf ~/Library/Developer/Xcode/DerivedData + maybe Xcode cache too flowdeck clean --all
Parse output Regex. Hope. Pray. --json

8 Commands. Not 84.

Apple's tooling:

xcodebuildxcrunsimctldevicectlinstrumentsxcode-selectios-deployxcresulttoolxctracealtoolnotarytool...

FlowDeck:

contextbuildruntestcleansimulatordevicelogs

Learn once. Use everywhere.

Output You Can Actually Use

xcodebuild output:
CompileSwift normal arm64 /Users/dev/MyApp/ContentView.swift (in target 'MyApp' from project 'MyApp')
    cd /Users/dev/MyApp
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend -frontend -c -primary-file /Users/dev/MyApp/ContentView.swift ...
    
/Users/dev/MyApp/ContentView.swift:42:15: error: cannot convert value of type 'String' to expected argument type 'Int'
        return someFunction(value)
                            ^~~~~

Plus 400 more lines.

FlowDeck output:
{
  "type": "build_started",
  "scheme": "MyApp",
  "destination": "iPhone 16"
}
{
  "type": "error",
  "file": "ContentView.swift",
  "line": 42,
  "column": 15,
  "message": "cannot convert 'String' to 'Int'"
}
{
  "type": "build_completed",
  "success": false,
  "duration": 8.2
}

Your CI parses it. Your AI agent understands it. You see what matters.

Speed Where It Counts

Operation xcodebuild FlowDeck
Scheme discovery 2-5 seconds Instant
Simulator lookup Spawns process, parses text Native, cached
Test discovery Requires build AST parsing, no build

These aren't benchmarks for marketing. These are the operations you run fifty times a day.

What Doesn't Change

Your .xcodeproj and .xcworkspace files
Your build settings and schemes
Your signing configuration
Your SPM dependencies
Your test targets

FlowDeck reads your project. It doesn't own it.

Need more proof?

Give it a go.

curl -sSL https://flowdeck.studio/install.sh | sh