xcui Reference (Scriptable Simulator UI and Accessibility Testing)
Reference for xcui, the simulator testing tool bundled with Axiom, which lets your assistant script UI and accessibility tests on the iOS simulator. It adds what AXe and simctl lack (waiting on conditions, asserting on the accessibility tree, toggling accessibility settings, handling permission dialogs, and computing VoiceOver announcements), and it forwards taps, typing, and swipes to AXe so input lands without you managing AXe's setup.
When to Use This Reference
Use this reference when:
- Looking up the flags for
xcui doctor,wait,assert,a11y set,a11y reset,dialog,voiceover, andresize sweep - Interpreting an exit code (
0pass,1assertion failure or wait timeout,2usage or environment error,8output-write error) - Checking which accessibility toggles
a11y setsupports and how each is applied (nativesimctl ui, ordefaults writeplus a relaunch) - Handling a system permission alert in a test, either by tapping the right button (
dialog acceptordismiss) or by granting the permission in advance so the alert never appears (dialog pregrant) - Validating VoiceOver announcements and focus order without capturing audio (
voiceover traverseandvoiceover assert) - Understanding how
xcuifinds the booted simulator, and why it refuses to guess when more than one is booted - Working out why a tap reported success but nothing happened
- Deciding what to drive with
xcuiand what to call onaxedirectly - Switching between JSON (the default) and
--humanoutput - Diagnosing why
doctorexits 2 (AXe missing or too old, no booted simulator, or several booted without--udid)
Example Prompts
Questions you can ask your assistant that will draw from this reference:
- "How do I wait for an element to appear on the simulator before asserting?"
- "How do I assert a VoiceOver label and trait on an element?"
- "How do I turn on Dynamic Type or Increase Contrast on the simulator?"
- "How do I dismiss the camera permission dialog in my test, or skip it entirely?"
- "How do I check the VoiceOver announcement order without listening to audio?"
- "What does
xcui doctorcheck, and how do I install AXe?" - "Why did
xcui assertexit 1?" - "Why isn't my accessibility toggle taking effect until I relaunch the app?"
What's Covered
- Invocation – In Claude Code,
xcuiis on yourPATHbecause Axiom's session hook adds the plugin'stools/folder; if the bare name isn't found,<plugin-root>/tools/xcuiworks, where<plugin-root>is the installed plugin's folder. Codex runs<plugin-root>/tools/xcui(there, the folder containing.codex-plugin/plugin.json) unlesscommand -v xcuifinds it onPATH. In Pi,xcuiisn't on yourPATHuntil you add it (Pi setup). MCP-only setups don't includexcui, and it has no MCP tool; without it, your assistant can still send input by calling AXe directly, butwait,assert,a11y,dialog,voiceover, andresize sweephave no AXe equivalent doctorsubcommand – Verifies AXe, Homebrew, Xcode, and a booted simulator;--installrunsbrew install cameroncooke/axe/axe, only when you ask;--humanfor prose. Exit 0 means a device command can run now, sodoctoralso fails when several simulators are booted with no--udid(every other subcommand refuses in that state) or when AXe is older than 1.7.0, the first version with--tap-style. Thebootedarray lists each device to pick a--udidfrom, and--udid <id>reports on a specific onewaitsubcommand –--for-element <id>,--gone <id>, or--idle, with--timeoutand--poll. It polls the accessibility tree until the condition holds or the deadline passes, the command-line equivalent ofwaitForExistenceassertsubcommand –--id <id>plus optional--label,--value,--trait, and--single.--singleasserts that the ID resolves to exactly one element, and--traitmatches a bare word (button,image) against the accessibility role or typea11y setanda11y reset– The five verified toggles and how each is applied (see the table below);--app <bundle-id>relaunches the app for the toggles that need itdialogsubcommand –acceptanddismissfind the frontmost system alert and tap the right standard button with a physical touch (a permission grant,OK,Cancel); a one-button alert is tapped for either intent, and matching ignores case and apostrophe style.pregrant <bundle-id> <service>…grants permissions throughsimctl privacyso the alert never appears. Exit0means handled,1means no actionable alertvoiceoversubcommand –traversewalks the tree in focus order and emits the computed announcement sequence (label, value, trait, plusdimmedwhen disabled).assert --sequence <file>compares the live sequence with an expected one, given as a JSON string array or a savedtraversereport, and reports every differing position, plus a note when the lengths differ. The sequence is computed from the accessibility tree, not captured speech (which the simulator doesn't expose), so use it to catch missing labels, wrong traits, and bad focus order- Input verbs –
tap,slider,type,swipe,drag,touch,gesture,button,key,key-sequence,key-combo, andscreenshotforward to AXe with the same flags, output, and exit code.xcuiadds--udidwhen you omit it and exactly one simulator is booted, and adds--tap-style physicaltotapwhen you pass no style. Preferxcui taptoaxe tap: it setsDEVELOPER_DIRfor you, so it keeps working under an Xcode whose SimulatorKit AXe can't load on its own. Onlyaxe describe-ui(the raw treexcuiparses) and AXe's streaming verbs are called directly; ifxcui doctorreports anaxe_developer_dir, prefix those withDEVELOPER_DIR=<value>, which is rarely needed since AXe 1.8.0 finds SimulatorKit in Xcode 27 on its own - Tap styles – A measured table of which SwiftUI targets each AXe tap style (
automatic,simulator,physical) actually activates, why a tap that does nothing still prints ✓, and why selectors tap the accessibility frame rather than the visible pixels resize sweepsubcommand – Needs an OS 27 simulator or device. It drives a resizable-app session across the breakpoints in--sizesand checks each one, in one JSON envelope: it holds the session and tears it down (even on SIGINT or SIGTERM), writes a PNG per breakpoint with--screenshot-dir, runs an accessibility check with--assert-id, fails on a clamped size with--strict, reports actual against requested size with anhonoredflag, retries each assertion through post-resize flakiness, and separates the threeappResizeCoreDeviceErrors (1001, 24001, 24004) into distinct fixes- Output envelope and exit codes – One compact JSON object with
toolandversionfirst; every subcommand accepts--humanfor prose. Exit0pass,1assertion failure or wait timeout,2usage or environment error,8output-write error - Command-line grammar – Flags may come in any order after the subcommand. Apart from the input verbs and
dialog pregrant, subcommands take no positional argument, soassert <id>fails with exit2and names the unexpected argument; writeassert --id …
Accessibility Toggles
a11y set --toggle <name> --value <…> supports the following toggles, all verified against the booted simulator. a11y reset clears them: it deletes the defaults keys, sets content_size to large, and sets increase_contrast to disabled.
| Toggle | Mechanism | --value | Relaunch |
|---|---|---|---|
dynamic-type | native simctl ui content_size | a size (large … accessibility-extra-extra-extra-large) | no |
increase-contrast | native simctl ui increase_contrast | on / off | no |
reduce-motion | defaults write com.apple.Accessibility ReduceMotionEnabled | on / off | yes (pass --app) |
reduce-transparency | defaults write com.apple.Accessibility ReduceTransparencyEnabled | on / off | yes (pass --app) |
voiceover | devicectl device settings voiceover | on / off | no |
differentiate-without-color and bold-text are not supported: simctl ui has no setter for them, the simulator ignores the candidate defaults keys, and devicectl device settings covers only appearance, audio, biometrics, reset, and VoiceOver. They are left out rather than shipped unverified.
Turning VoiceOver on is not the same as xcui voiceover
a11y set --toggle voiceover starts the real screen reader. xcui voiceover traverse computes the announcement sequence from the accessibility tree with VoiceOver off: it's deterministic, makes no speech, steals no focus, and is the one you want in CI. Use the toggle only when you need the device in a genuine VoiceOver state.
Documentation Scope
This page documents the xcui-ref skill in the axiom-tools suite. xcui is Axiom's bundled tool for scripted simulator UI and accessibility testing.
- For the input primitives
xcuiforwards to, see AXe (Simulator Automation) - For device state such as biometrics, orientation, and location, use
devicectl; see Device Control.xcuithen checks the on-screen result that state produces
Related
- simulator-tester – The agent that drives
xcuilive: setting toggles, waiting, and asserting on the tree - accessibility-auditor – Scans your source code for accessibility problems, the static counterpart to live validation with
xcui - /axiom:ui – The command that runs
xcuifor you - xclog-ref, xcprof-ref, and xcsym-ref – References for the other bundled tools; the Tools overview covers axbuild and xcproject