The full iOS toolkit
in a conversation.
Pepper injects into iOS apps and hands your agent the same tools you'd reach for — view hierarchy, network, memory, performance, accessibility, the works. 60+ MCP tools. pip install pepper-ios and go.
> Go to the Settings screen and see what's there. ▸ look() Screen: navigation_stack (9 interactive, 4 text) seg "Trending" → tap text:"Trending" btn "Sheryl Weikal, Right wing tech…" → tap text:"Sheryl Weikal…" seg "Settings" → tap text:"Settings" I can see the main navigation. I'll tap into Settings. ▸ tap(text: "Settings") Action: Tapped Settings Screen: navigation_stack Title: "Settings" (15 interactive, 3 text) btn "App Icon" → tap text:"App Icon" btn "Display Settings" → tap text:"Display Settings" Here's the Settings screen — 15 interactive elements including App Icon, Display Settings, and more. What do you want me to look at?
How it works
pepper-ctl deploy injects a dylib into the simulator process using DYLD_INSERT_LIBRARIES. The dylib starts a WebSocket server inside the app. Your MCP client connects to it. Because Pepper runs in-process, it has access to the full ObjC runtime, live view hierarchy, object graphs, network delegates, and the HID event system. All touch input goes through native IOHIDEvent injection — the same path real fingers take.
What you can tell your agent
"There's a crash three screens deep in the checkout flow but only when the cart has 10+ items. Figure out what's going on and fix it."
"Build the new profile editor screen. Make sure empty fields, validation errors, and the success state all look right before you're done."
"Users are reporting a white flash on launch in dark mode. Find it and fix it."
"The feed is dropping frames on scroll. Find the bottleneck and fix it."
"Somebody shipped a retain cycle in the messaging flow. Track it down, fix it, and make sure it's actually gone."
"Go through every screen in the settings tab and fix any accessibility violations."
> Users are reporting the app freezes after you post a reply in a long thread. I can't reproduce it with short threads. Figure it out. I'll open a long thread and try to reproduce it. ▸ tap(text: "Trending") ▸ tap(text: "Show this thread") ▸ scroll(direction: "down", distance: 8000) ▸ tap(text: "Reply") ▸ input_text(text: "Testing reply") ▸ tap(text: "Post") Reproduced — the UI is frozen. Let me check what's blocking main thread. ▸ hangs() ⚠ Main thread blocked 4.2s ThreadListViewController.reloadEntireThread() — re-fetching all 847 replies synchronously after post ▸ network() GET /api/v1/threads/90281/replies — 3.9s, 847 items Called from reloadEntireThread() on main queue Found it. After posting a reply, reloadEntireThread() re-fetches every reply synchronously on main. Short threads are fast enough to mask it. I need to make it fetch on a background queue and only insert the new reply locally. ▸ Read ThreadListViewController.swift ▸ Edit ThreadListViewController.swift ▸ build_sim() ▸ deploy_sim() Rebuilt and deployed. Re-running the same steps to verify. ▸ scroll(direction: "down", distance: 8000) ▸ tap(text: "Reply") ▸ input_text(text: "Testing reply") ▸ tap(text: "Post") ▸ hangs() ✓ No main thread hangs detected Fixed. The post callback was calling reloadEntireThread() which fetched all 847 replies synchronously on main. Changed it to append the new reply to the data source and do a single row insert. Verified on the same long thread — no hang after posting.
60+ tools
look · tap · scroll · swipe · gesture · input_text · toggle · navigate · back · dismiss · find · verify · screenshot · snapshot · diff · heap · layers · console · network · timeline · crash_log · vars_inspect · constraints · accessibility_audit · responder_chain · renders · perf · hangs · animations · concurrency · defaults · clipboard · keychain · cookies · coredata · storage · sandbox · flags · locale · push · orientation · appearance · dynamic_type · status · lifecycle · notifications · wait_for · wait_idle · record · script · hook · build_sim · deploy_sim
Works with Claude Code, Cursor, Claude Desktop, or any MCP client.