Skip to content

goliajp/smix

Repository files navigation

smix

License Rust

AI-native iOS Simulator automation library and CLI, written in Rust.

smix drives iOS-Simulator apps through a typed Rust API designed for LLM authoring: explicit selectors, AI-readable failure messages with visible-element context and edit-distance suggestions, host-side resolve with Apple-native event injection, and an MCP server entry for direct Claude Code integration.

The project pivoted from TypeScript to Rust in v3 (May 2026); the original TS implementation is preserved as a port reference under legacy/. The canonical implementation lives in crates/ as a cargo workspace following the mailrs stone-vs-cement layout convention.

Quickstart

# Probe environment (Xcode command-line tools + Simulator state).
cargo run --release -p smix-cli -- doctor

# List simulators (or use `--json` for machine-readable output).
cargo run --release -p smix-cli -- sim list
// In your own Rust test or binary:
use smix_sdk::{App, text, KeyName};
use std::time::Duration;

# async fn demo() -> Result<(), smix_sdk::ExpectationFailure> {
let app = App::connect_to_runner(22087).await?
    .with_udid("4F0B35D2-03F0-4A8F-B729-09072153E8AE");
app.launch("com.example.app").await?;
app.wait_for(&text("Login"), Duration::from_secs(5)).await?;
app.tap(&text("Login")).await?;
app.fill(&text("Email"), "user@example.com").await?;
app.press_key(KeyName::Return).await?;
app.assert_visible(&text("Dashboard")).await?;
# Ok(())
# }

The smix CLI binary and the smix-mcp MCP server are built from this workspace. The SmixRunner (Swift sub-project at swift-bridge/) provides the sim-side XCUITest runner the Rust client talks to over HTTP.

Crate layout

Following mailrs's stone-vs-cement convention:

  • Stones are zero-project-coupling, RFC/protocol-bounded crates — a non-smix Rust project could adopt them.
  • Cement is smix-specific business code (lifecycle conventions, wire contracts with our Swift runner, CLI / MCP entry binaries).

Stones (community-publishable)

Crate Role
smix-core Barrel + shared placeholder
smix-screen A11yNode / Rect / Role / ElementSummary + visibility primitives
smix-selector Structured Selector enum + match_text + describe_selector
smix-selector-resolver DFS + spatial + visibility resolver (with compile cache)
smix-input KeyName + SwipeDirection enums
smix-error AI-readable ExpectationFailure + build_suggestions + edit-distance
smix-recorder-ir IRAction enum + JSON serialization
smix-simctl Generic xcrun simctl child_process wrapper

Cement (smix-specific)

Crate Role
smix-runner-client HTTP IPC client to swift-bridge/SmixRunnerCore
smix-driver Decide layer (5s implicit wait, scroll loop, dispatch conventions)
smix-sdk Public App surface + ergonomic selector helpers + matchers
smix-cli smix binary (clap-based CLI)
smix-mcp smix-mcp binary (rmcp 1.7 stdio MCP server)

Performance

Following the mailrs convention, every hot-path primitive carries a tests/perf_gate.rs hard ceiling and a benches/<name>.rs criterion bench. All numbers come from criterion bench medians on M-series macOS (see PERFORMANCE.md for the methodology and the TS baseline comparison table).

Sample v3.1 measurements (Rust release vs TS V8 baseline):

Operation TS (ns) Rust (ns) Speedup
is_visible_enough (in-view) 21.2 0.996 21×
is_visible_enough (zero-bounds reject) 20.5 0.449 46×
match_text_compiled (string label hit) 36.8 4.89 7.5×
match_text_compiled (string miss, 6-field scan) 41.4 3.53 12×
resolve_selector (id base, 100-node tree miss) 3,234 198 16×
dfs_collect (100-node tree composite) 788 233 3.4×

See PERFORMANCE.md for the full table across 25+ operations.

Real-sim end-to-end

The insight_parity example exercises 10 real-world iOS flows against an installed app — the gate v1.9 closed at 5-round strict 10/10, used as the Rust-rewrite business-level re-verification target for v3.4.

# Once you have: a booted sim, the insight RN app installed, Metro
# bundler running, and the SmixRunnerCore swift binary launched on
# the sim:
export SMIX_UDID="$(xcrun simctl list devices booted | awk '/Booted/{print $NF}' | tr -d '()' | head -1)"
./scripts/insight-parity.sh

The script does env / runner / Metro probes, runs the example, and on failure captures a sim screenshot to /tmp/insight-fail-<ts>.png for follow-up dig.

Documentation

Project constraints

smix ships with hard architectural rules; the full list lives in CLAUDE.md. Highlights:

  • iOS Simulator only. Real-device automation is out of scope.
  • No xpath / no raw-coordinate selector surface. Selectors are structured (text / id / label / role+name / focused / anchor-only).
  • No bare sleep API. All wait surfaces are explicit and bounded.
  • AI-readable failure messages. ExpectationFailure::to_prompt emits structured output a coding agent can act on.
  • Runner port is localhost-only. No 0.0.0.0 bind (compliance gate set in v1.2).

License

Licensed under either of

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.