CLAUDE.md#
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview#
AXe is a comprehensive CLI tool for interacting with iOS Simulators using Apple's Accessibility APIs and HID (Human Interface Device) functionality. It's built on top of Meta's idb frameworks and provides a clean, modern Swift interface for simulator automation.
Development Commands#
Building the Project#
# Build with Swift Package Manager (recommended for development)
swift build
# Run directly without building
swift run axe [command]
# Build release version
swift build -c release
# Build frameworks from IDB (only needed if updating IDB dependencies)
./scripts/build.sh frameworks
Testing Commands#
# Run the playground app to test functionality
open AxePlaygroundApp/AxePlayground.xcodeproj
# Test a specific command
swift run axe tap -x 100 -y 200 --udid [SIMULATOR_UDID]
# Get simulator UDID
xcrun simctl list devices
Testing with AxePlaygroundApp#
AxePlaygroundApp is an iOS test application that provides visual feedback for AXe command testing. It includes multiple test screens for different interaction types.
Available Test Screens#
tap-test: Displays tap coordinates and countswipe-test: Shows swipe start/end coordinates and directiontext-input: Text field for typing validationkey-press: Individual key press validationkey-sequence: Key sequence validationgesture-presets: Gesture detection and validationtouch-control: Touch down/up/move event tracking
Launching to Specific Test Screens#
# Terminate any existing instance
xcrun simctl terminate [SIMULATOR_UDID] com.cameroncooke.AxePlayground
# Launch directly to a specific test screen
xcrun simctl launch [SIMULATOR_UDID] com.cameroncooke.AxePlayground --launch-arg "screen=tap-test"
# Example workflow for tap testing
xcrun simctl launch B34FF305-5EA8-412B-943F-1D0371CA17FF com.cameroncooke.AxePlayground --launch-arg "screen=tap-test"
sleep 2 # Wait for app to load
swift run axe tap -x 200 -y 400 --udid B34FF305-5EA8-412B-943F-1D0371CA17FF
# Capture result for validation
swift run axe describe-ui --udid B34FF305-5EA8-412B-943F-1D0371CA17FF > result.json
Test Screen Views in AxePlaygroundApp#
The playground app includes these view files:
TapTestView.swift: Validates tap coordinates and countsSwipeTestView.swift: Tracks swipe gesturesTextInputView.swift: Text input validationKeyPressView.swift: Individual key press testingKeySequenceView.swift: Key sequence testingGesturePresetsView.swift: Gesture preset validationTouchControlView.swift: Touch event sequences
Architecture Overview#
Command Structure#
The project uses Apple's ArgumentParser framework with async/await support. Each command:
- Extends
AsyncParsableCommand - Validates input in
validate() - Executes logic in async
run() - Uses common setup via
AsyncParsableCommand+Setupextension
Key Components#
HIDInteractor (Sources/AXe/Utilities/HIDInteractor.swift):
- Central component for simulator interaction
- Uses
@MainActorfor thread safety - Bridges Swift async/await with FBFuture APIs
FutureBridge (Sources/AXe/Utilities/FutureBridge.swift):
- Critical adapter between Objective-C FBFuture and Swift async/await
- Type-safe conversions for NSArray, NSDictionary, NSNumber, etc.
- Handles cancellation and error propagation
AccessibilityFetcher (Sources/AXe/Utilities/AccessibilityFetcher.swift):
- Retrieves UI hierarchy from simulators
- Returns structured JSON for automation
Framework Dependencies#
The project depends on Meta's idb frameworks, included as XCFrameworks:
- FBControlCore
- FBSimulatorControl
- FBDeviceControl
- XCTestBootstrap
These are in build_products/XCFrameworks/ and are automatically handled by Swift Package Manager.
Current Issues & Next Steps#
Race Condition Investigation (from INVESTIGATION.md)#
The project has a known race condition when using FBSimulatorControl directly. Based on investigation, the issue stems from differences between how CompanionLib handled HID events vs our direct approach:
Key Differences Found:
- Serial Queue Synchronization: CompanionLib used a dedicated serial queue for operations
- Private Framework Loading: CompanionLib explicitly loaded private frameworks before HID operations
- Target Initialization: CompanionLib used
warmUp: truewhich may initialize important state
Priority Fixes Needed:
- Add private framework loading before HID operations
- Implement serial queue synchronization for HID operations
- Investigate target warmup functionality
- Ensure HID connection persistence
Adding New Commands#
- Create new file in
Sources/AXe/Commands/ - Extend
AsyncParsableCommand - Add validation logic in
validate() - Implement async
run()method - Register command in
main.swift
Example structure:
struct MyCommand: AsyncParsableCommand {
static let configuration = CommandConfiguration(
commandName: "my-command",
abstract: "Description of command"
)
@Option var parameter: String
func validate() throws {
// Validation logic
}
func run() async throws {
try await performGlobalSetup()
let logger = try AxeLogger()
// Command implementation
}
}
Important Patterns#
Error Handling: Always validate inputs before execution. Use CLIError for command-specific errors.
Async/Await: All commands and utilities use Swift concurrency. Use FutureBridge when interfacing with FBFuture-based APIs.
Logging: Use AxeLogger for consistent output. Pass logger instance through method calls.
Simulator Targeting: Always verify simulator exists before interaction using SimulatorUtilities.
Testing Strategy#
The project includes comprehensive test plans in Docs/:
AXE_COMPREHENSIVE_TEST_PLAN.md: Detailed test cases for all commandsUSAGE_EXAMPLES.md: Real-world usage patterns and examples
Key testing components:
- AxePlaygroundApp: iOS test app providing visual feedback for automation testing
- Test screens for each interaction type (tap, swipe, text, gestures, etc.)
- Exact validation of coordinates, text, and timing
Building for Distribution#
The scripts/build.sh script handles the complete build process including:
- Building IDB frameworks
- Creating XCFrameworks
- Building AXe executable
- Code signing with Developer ID
- Apple notarization
For releases, use: ./scripts/create-release.sh
Command Reference#
Available Commands#
describe-ui: Extract accessibility informationlist-simulators: List available simulatorstap: Tap at coordinates with timing controlswipe: Swipe gestures with customizable parameterstype: Type text via direct input, stdin, or filekey: Press individual keys by HID keycodekey-sequence: Execute key sequencestouch: Low-level touch down/up eventsbutton: Hardware button simulationgesture: Gesture presets (scroll, swipe patterns)
Gesture Presets#
- Scrolling:
scroll-up,scroll-down,scroll-left,scroll-right - Navigation:
swipe-from-left-edge,swipe-from-right-edge, etc.
All commands support --pre-delay and --post-delay for timing control.