Skip to content

jsj/xc-cli

Repository files navigation

xc-cli cover

xc

iOS macOS Swift Release

One explicit CLI for the full Apple development lifecycle -- from installing Xcode to managing apps on the store.

curl -fsSL https://github.com/jsj/xc-cli/releases/latest/download/install.sh | sh

Requires macOS 14+ and Xcode Command Line Tools.

Why xc exists

Apple development data and tooling is spread across xcodebuild, simctl, devicectl, xcrun, xcode-select, App Store Connect, and half a dozen other surfaces. Building an app and running it on a simulator means stitching together four commands:

xcodebuild -workspace MyApp.xcworkspace \
  -scheme MyApp \
  -destination 'platform=iOS Simulator,name=iPhone 16' \
  -derivedDataPath ./build build

xcrun simctl boot "iPhone 16"
xcrun simctl install "iPhone 16" ./build/Build/Products/Debug-iphonesimulator/MyApp.app
xcrun simctl launch "iPhone 16" com.example.MyApp

With xc, the common case is one command:

xc run --json

xc resolves your workspace, picks the right simulator, boots it, builds, installs, and launches. The --json flag emits typed NDJSON events so agents and scripts can consume the output directly:

{"event":"started","command":"run","payload":{"status":"started","details":"build and launch"}}
{"event":"simulator_booted","command":"run","payload":{"udid":"...","name":"iPhone 16","state":"booted"}}
{"event":"build_succeeded","command":"run","payload":{"module":"MyApp","duration_ms":4200}}
{"event":"app_installed","command":"run","payload":{"bundle_id":"com.example.MyApp"}}
{"event":"result","command":"run","payload":{"status":"ok","duration_ms":8340,"details":"Launched on iPhone 16"}}

When something goes wrong

If the project is ambiguous or a runtime is missing, xc fails with a structured error that tells you (or your agent) exactly what to do next:

{
  "event": "error",
  "command": "run",
  "payload": {
    "code": "E_RUNTIME_UNAVAILABLE",
    "message": "No matching simulator runtime",
    "details": "No booted simulator matches the resolved scheme destination.",
    "remediation": "Run `xc runtime simulator --boot <UDID>` or `xc status --json` to inspect available runtimes.",
    "retryable": true,
    "suggested_commands": ["xc status --json", "xc runtime simulator --boot <UDID>"]
  }
}

Exit codes are stable: 0 success, 2 invalid usage, 3 config missing, 4 runtime unavailable, 5 build/test/launch failure, 6 UI assertion failure, 70 internal error.

Try it on your existing project

You do not need to replace your current setup. Point xc at any Xcode project or workspace and see what it finds:

cd ~/MyApp
xc status --json        # what xc can see: workspace, schemes, simulators, devices
xc run --json           # build and launch
xc test --json          # run tests

No config files, no Fastfile, no Gemfile. If xc status resolves your project, xc run and xc test will work.

Install it into your agent

xc is not just a CLI you call manually. It can also become part of your agent's toolbelt so the agent can build, preview, inspect, and ship Apple apps through one stable interface.

xc skills install

Once installed as a skill, your agent can use xc as its native Apple development surface instead of falling back to ad hoc xcodebuild, simctl, shell scripts, or Fastlane glue.

What xc covers

The point of xc is to be the full corpus of Apple development work in one CLI. Build, test, and run are where most developers start, but the same contract extends across the entire lifecycle:

Preview -- Render SwiftUI previews without opening Xcode. An agent can build your UI, then render and visually review every screen across devices, color schemes, dynamic type sizes, and orientations -- all without a human opening Xcode or tapping through the app.

xc preview render "ContentView" --device "iPhone 17" --color-scheme both --json

UI automation -- Accessibility-driven sessions. Read the AX tree, tap by label, type text, assert state, capture screenshots.

xc ui start --json
xc ui tap --label "Sign In" --json
xc ui screen --json

Ship -- TestFlight, App Store, Xcode Cloud.

xc release publish testflight --ipa ./build/App.ipa --json

Reviews -- Draft and send App Store review replies.

xc reviews draft --app-name "MyApp" --stars 1 \
  --body "App crashes on launch." \
  --support-email support@example.com --json

ASO -- Keyword rankings, ratings, competitor analysis.

xc aso search-rankings --keyword "habit tracker" --store us --json

Docs -- Apple Developer Documentation from the terminal.

xc docs call search_apple_docs --args '{"query":"SwiftUI View"}' --json

Inspect -- Project metadata, device logs, runtime management, network monitoring, Instruments profiling.

Agent integration -- Install xc as a skill so your agent can use the same Apple workflow surface directly.

Run xc help --json for the full command catalog.

Why this is better than what you already have

Structured output instead of text parsing. Every command supports --json. Every error includes a code, a message, remediation text, and suggested commands. No regex, no scraping.

Explicit failures instead of silent mismatches. When something is wrong, the error tells you what to provide and how. Agents can self-correct on the first retry instead of guessing.

One binary, native Swift. xc orchestrates Apple tooling directly. No Ruby, no Node, no shelling out to Fastlane. The only external dependencies are Apple's own tools.

Broader than build/test. The same CLI and the same JSON contract cover the full lifecycle -- preview rendering, UI automation, docs, release, reviews, ASO, and Xcode Cloud. One tool, one output shape, one error model.

Development

swift build
swift test

ASO cache backend

xc defaults to the hosted cache worker at https://db.xc.jsj.sh. To override it for local or alternate deployments:

export XC_ASO_BACKEND_URL="https://db.xc.jsj.sh"

If you later protect the worker with a bearer token, also set:

export XC_ASO_BACKEND_TOKEN="your-token"

License

MIT