Baguette
Bon appétit.
Headless iOS Simulator manager + host-side input injection for iOS 26.
A single Swift CLI — baguette — plus a self-contained web UI
that gives you full headless control of an iOS simulator without
opening Xcode or Simulator.app. Boot devices, stream their screens
at 60 fps, dispatch taps / swipes / multi-finger gestures / system
gestures / keyboard / hardware buttons, tail the unified log,
inspect the accessibility tree, take screenshots and recordings, and
— as of 0.1.72 — pipe your Mac webcam into the simulator's camera
APIs.
Demo
https://github.com/user-attachments/assets/e904413f-16bb-4b3d-86d5-162333403cee
https://github.com/user-attachments/assets/c49c9f4b-0e4b-47ea-9272-3223b1ac7739
https://github.com/user-attachments/assets/65dc62ee-f0c7-48fb-9c57-5bd267c8c02f
The raw clip lives at assets/demo.mp4 — drag
it into a GitHub web edit of this README to upload as a CDN-hosted
video and replace the line above with the auto-generated URL.
- Frame streaming — MJPEG or H.264 / AVCC over stdout or WebSocket.
Runtime-tunable bitrate / fps / scale. In-browser recording (MP4)
composites the bezel + screen + gesture overlays into one file.
- Host-HID input — taps / swipes / streaming 1- and 2-finger
gestures / pinch / pan / scroll / Mac keyboard / hardware buttons
(home, lock, power, volume, action, plus Apple Watch's digital
crown + side button) — all through SimulatorKit's private symbols
with the iOS-26 calling conventions. The iOS-26 streaming-touch +
edge-gesture path uses
IOHIDDigitizerDispatch so home-indicator
swipes, app-switcher drags, and Notification Center / Lock Screen
pull-downs all fire the real iOS recognizers live. No dylib
injection on this path; no DYLD_INSERT_LIBRARIES to manage.
- Camera (new in 0.1.72) — pipe a Mac webcam directly into the
iOS simulator's
AVCaptureVideoPreviewLayer, AVCapturePhotoOutput,
and UIImagePickerController. Pick a camera in the browser's
Camera card, click Start, the iOS app sees real frames. One
ObjC dylib (VirtualCamera.dylib, vendored from
asc-pro/SimCam)
loaded into every sim-launched app via DYLD_INSERT_LIBRARIES;
baguette pumps BGRA frames through a shared-memory ring buffer.
See docs/features/camera.md.
- Device orientation —
baguette orientation --udid <X> portrait
rotates a booted simulator. Wire JSON + a one-click rotate button
on the focus-mode toolbar. Fires a GSEventTypeDeviceOrientationChanged
mach message at PurpleWorkspacePort, bypassing SimulatorKit's
NSView path so the host stays headless.
- Accessibility tree —
baguette describe-ui returns the
on-screen AX tree as JSON (per-node role, label, value,
identifier, frame in device points). Hit-test mode (--x --y)
returns the topmost node under a coordinate. Powered by the
private AccessibilityPlatformTranslation framework with a
bridgeTokenDelegate we install ourselves.
- Live unified-log stream —
baguette logs --udid <X> streams
os_log output to stdout; WS /simulators/:udid/logs does the
same to the browser's Logs panel. Predicate / bundle-id filters.
- Standalone web UI —
baguette serve opens
http://localhost:8421/simulators with a list page, a focus-mode
per-device view, a sidebar stream view, the Camera card, an
Accessibility inspector overlay, a Logs panel, and in-browser
recording. All wrapped by a small JS SDK
(Resources/Web/baguette/) — const sim = await Baguette.use({…}); sim.mount(container); — that hangs each part (screen, buttons,
keyboard, …) off one Simulator instance.
- Device farm —
http://localhost:8421/farm renders every booted
simulator in a wall / grid / list with filtering + sorting. Click
a tile to focus it for full-quality streaming + input through the