
chofi is a JSON-first CLI for iOS, Android, Expo, and React Native workflows — simulator management, builds, tests, screenshots, device operations, and Maestro UI automation.
- JSON-first: Every command emits NDJSON events for both humans and machines
- Planning before execution:
plan commands show what would happen; execution requires explicit confirmation
- Clean-room: Inspired by public CLI patterns, but owned code with no proprietary dependencies
- Maestro-native: UI automation flows through Maestro's open-source local runner
- Subprocess-based: Uses
xcrun, simctl, devicectl, and maestro via typed subprocess calls — no native framework linking
npm install -g @ramarivera/chofi
# or
pnpm add -g @ramarivera/chofi
# or
npx @ramarivera/chofi context --json
# Discover your project
chofi context --json
# Boot a simulator
chofi sim boot "iPhone 17 Pro" --json
# Take a screenshot
chofi sim screenshot "iPhone 17 Pro" --output ./shot.png --json
# Run Maestro flow
chofi maestro run flows/smoke.yaml --json
| Command |
Description |
chofi context --json |
Project metadata, detected platforms, tool availability |
chofi doctor --json |
Health checks (Xcode, simctl, node, pnpm, typecheck) |
chofi plan run ios --json |
Show what an iOS run would do |
chofi plan run maestro --json |
Show what Maestro flows would run |
| Command |
Description |
chofi sim list --json |
List all simulators |
chofi sim runtime --json |
List available runtimes |
chofi sim device-types --json |
List available device types |
chofi sim boot <target> --json |
Boot simulator (fuzzy match) |
chofi sim shutdown <target> --json |
Shutdown simulator |
chofi sim open <target> --json |
Open Simulator.app GUI |
chofi sim screenshot <target> --output <path> --json |
Screenshot (PNG) |
chofi sim screenshot <target> --output <path> --format jpeg --json |
Screenshot (JPEG) |
chofi sim erase <target> --confirm --json |
Erase simulator data |
chofi sim create <name> <deviceType> <runtime> --json |
Create simulator |
chofi sim clone <target> <newName> --json |
Clone simulator |
chofi sim delete <target> --confirm --json |
Delete simulator |
chofi sim prune --confirm --json |
Remove unavailable simulators |
chofi sim set-appearance <target> <dark|light> --json |
Set appearance |
chofi sim clear-cache <target> --json |
Clear simulator cache |
chofi sim add-media <target> <paths...> --json |
Add photos/videos to Photos |
chofi sim record start <target> <path> --json |
Start video recording |
chofi sim record stop <target> --json |
Stop video recording |
| Command |
Description |
chofi device list --json |
List connected devices |
chofi device list --platform connected --json |
Filter by status |
| Command |
Description |
chofi app install <udid> <path> --json |
Install .app bundle |
chofi app launch <udid> <bundleId> --json |
Launch app |
chofi app launch <udid> <bundleId> --json -- <args...> |
Launch app with app arguments and report verified argv |
chofi app launch <udid> <bundleId> --stability-recheck-ms 3500 --json |
Require the launched PID to survive a longer post-launch settle window |
chofi app terminate <udid> <bundleId> --json |
Terminate app |
chofi app terminate <udid> <bundleId> --force --json |
Force kill (SIGKILL) |
chofi app terminate-all <udid> --force --json |
Kill ALL apps |
chofi app uninstall <udid> <bundleId> --json |
Uninstall app |
chofi apps list <udid> --json |
List running apps |
chofi apps prune <udid> --json |
Remove stale registry entries |
| Command |
Description |
chofi logs <udid> --json --timeout <ms> |
Stream simulator/device logs |
chofi logs <udid> --json --timeout <ms> --bundle-id <bundleId> |
Stream app-focused logs |
chofi logs <udid> --json --timeout <ms> --predicate <predicate> |
Stream logs matching an explicit NSPredicate |
| Command |
Description |
chofi build --scheme <scheme> --json |
Build via xcodebuild |
chofi build --scheme <scheme> --progress --json |
Streaming build output |
chofi build --scheme <scheme> --derived-data-path <path> --json |
Build with an explicit DerivedData path |
chofi build --scheme <scheme> --json -- CODE_SIGNING_ALLOWED=NO |
Forward extra xcodebuild settings/args |
chofi test --scheme <scheme> --json |
Run tests |
chofi test --scheme <scheme> --only <test> --json |
Run specific tests |
chofi test --scheme <scheme> --skip <test> --json |
Skip specific tests |
chofi test --scheme <scheme> --retry --json |
Retry failed tests |
chofi test --scheme <scheme> --progress --json |
Real-time test progress |
chofi test --scheme <scheme> --result-bundle-path <path> --json |
Preserve an explicit .xcresult bundle path in failure JSON |
chofi test --scheme <scheme> --json -- CODE_SIGNING_ALLOWED=NO -quiet |
Forward extra xcodebuild settings/args after -- |
chofi test discover --scheme <scheme> --json |
Discover available tests |
chofi clean --scheme <scheme> --json |
Clean build artifacts |
chofi clean --scheme <scheme> --derived-data --json |
Clean derived data |
| Command |
Description |
chofi run ios --json |
Build and run on iOS simulator |
chofi run ios --no-build --json |
Skip build, just run |
chofi run ios --launch-env KEY=value --json |
Pass launch env vars |
chofi run android --confirm --json |
Build and run on Android |
| Command |
Description |
chofi maestro check --json |
Check Maestro installation |
chofi maestro run <flow> --json |
Run a Maestro flow |
chofi maestro continuous <flow> --json |
Run in continuous mode |
chofi maestro hierarchy --json |
Dump UI hierarchy |
chofi maestro record <flow> --json |
Record a test session |
chofi maestro driver-setup --json |
Setup Maestro driver |
chofi maestro start-device --platform ios --json |
Start Maestro device |
| Command |
Description |
chofi project build-config --json |
List build configurations |
chofi project schemes --json |
Auto-detect schemes |
| Command |
Description |
chofi config get <key> --json |
Get config value |
chofi config set <key> <value> --json |
Set config value |
chofi config reset --confirm --json |
Reset config |
Every command emits newline-delimited JSON events:
{"schemaVersion":"0.1.0","tool":"chofi","event":"command_started","phase":"sim.boot","timestamp":"2026-05-03T00:00:00.000Z","data":{"target":"iPhone 17 Pro"}}
{"schemaVersion":"0.1.0","tool":"chofi","event":"command_completed","phase":"sim.boot","status":"passed","timestamp":"2026-05-03T00:00:02.000Z","data":{"target":"iPhone 17 Pro"}}
{"schemaVersion":"0.1.0","tool":"chofi","event":"summary","phase":"sim.boot","status":"passed","timestamp":"2026-05-03T00:00:02.000Z","data":{"target":"iPhone 17 Pro"}}
| Event |
Description |
command_started |
Command began execution |
command_completed |
Success — contains result data |
command_failed |
Failure — contains message and recoverySuggestion |
summary |
Final event (always emitted) |
tool_checked |
Tool availability report |
plan |
Execution plan (non-executing) |
progress |
Build/test progress stream |
chofi
├── src/
│ ├── cli.ts # Commander.js CLI parsing & routing
│ ├── runtime.ts # Execution orchestrator (20+ operations)
│ ├── drivers/
│ │ ├── apple.ts # simctl, xcrun, devicectl, xcodebuild
│ │ ├── maestro.ts # Maestro CLI wrapper
│ │ └── expo.ts # Expo CLI wrapper
│ ├── spawn.ts # ProcessSpawner abstraction (testable)
│ ├── events.ts # NDJSON event envelope
│ ├── discovery.ts # Workspace & tool discovery
│ ├── planning.ts # Non-executing command plans
│ ├── safety.ts # Explicit confirmation gates
│ ├── config.ts # .chofi.json persistence
│ └── errors.ts # Structured error hierarchy
└── test/
├── drivers/ # Driver unit tests
├── e2e.test.ts # End-to-end CLI tests
├── integration.test.ts # Live tests (CHOFI_LIVE=1)
└── *.test.ts # Unit tests
Dangerous operations require explicit confirmation:
| Command |
Gate |
sim erase |
--confirm |
sim delete |
--confirm |
sim prune |
--confirm |
run ios (device) |
--confirm |
run android |
--confirm |
config reset |
--confirm |
Create .chofi.json in the project root:
{
"scheme": "MyApp",
"workspace": "MyApp.xcworkspace",
"destination": "platform=iOS Simulator,name=iPhone 17 Pro"
}
Or use environment variables:
| Variable |
Purpose |
CHOFI_SCHEME |
Default Xcode scheme |
CHOFI_WORKSPACE |
Default Xcode workspace |
CHOFI_PROJECT |
Default Xcode project |
CHOFI_DESTINATION |
Default build destination |
| Variable |
Purpose |
CHOFI_LIVE |
Set to 1 to enable live integration tests |
# Install dependencies
pnpm install
# Run all tests
pnpm test
# Run live integration tests
CHOFI_LIVE=1 pnpm test:live
# Typecheck
pnpm typecheck
# Build
pnpm build
# Run locally
node dist/cli.js context --json
This package publishes through GitHub Actions trusted publishing from .github/workflows/publish.yml.
To publish a new release, bump package.json, commit, and push to master. The workflow uses Node 24 with npm 11+, installs dependencies with pnpm, runs typecheck/tests, builds dist/, performs an npm pack dry-run, skips already-published versions, and publishes unpublished versions to npm.
The npm trusted publisher should be configured for:
- Package:
@ramarivera/chofi
- Repository:
ramarivera/chofi
- Workflow:
.github/workflows/publish.yml
- Environment: blank unless the workflow is changed to require one
MIT