Skip to content
bmcreationsPublic

About

Android devices, emulators and iOS simulators from your Mac, live in any browser at 60 fps, shared between you and your agents over a CLI, MCP or HTTP.

Topics

Resources

Security policy

Stars

12 stars

Watchers

0 watching

Forks

Repository files navigation

loupe: your Android devices, emulators and iOS simulators, live in any browser, shared with your agents

macOS Go 1.26 MCP, CLI and HTTP for agents CI status Latest release Apache 2.0 license

The device on your desk, in your hand.
Stream Android devices, emulators and iOS simulators from your Mac to any browser at 60 fps, with live touch.
Agents drive it through a CLI, MCP or HTTP. In the browser you see each tap coming, and your touch takes over.


Quick start

brew install bmcreations/tap/loupe
brew services start loupe
open "http://localhost:18456/?token=$(cat ~/Library/Caches/loupe/token)"

The picker lists every Android device on adb and every AVD you have installed, booted or not. Open one to stream it. iOS simulators need simcap, built with your own Xcode:

brew install --HEAD bmcreations/tap/simcap && brew services restart loupe

Without a certificate the service answers on loopback only. To reach it from your phone, give it TLS: docs/getting-started.md walks through it with Tailscale, then pairing a phone and connecting an agent.

Work on the same device as your agent

Three views of the web client: the banner reads claude is driving with a Take over button while the agent's cursor sits on Sign in; a finger on the screen and the banner reads claude is waiting for you; a red box around part of the screen with the Flag for agent card open

Open a device in the browser while an agent drives it, and the web client shows who has control and where the agent is about to tap.

  1. The agent claims the device. A second agent gets claimedBy and picks another one.
  2. In the browser, you see its cursor before it taps. The banner reads "claude is driving", and Take over gives you control. Between an agent's calls the cursor stays where it last acted for 20 seconds, dimmed.
  3. Touch the screen and you're driving. The agent's input is refused with humanHeld and a retry time, and the banner reads "claude is waiting for you". Mark a device hands off to refuse agents entirely.
  4. Box what's wrong and send it. Flag for agent sends your note, the screenshot and the UI tree. An interrupt stops the agent mid-task.

The cursor, the banner and Take over are only in the browser. An agent working alone sees none of them: the CLI, MCP or HTTP just answers claimedBy or humanHeld. Claims and the human hold are in docs/agent-api.md, flags and interrupts in docs/flags.md.

Drive it from a shell or an agent

A terminal session: loupe targets lists devices, loupe ui finds the Sign in button's center, loupe tap taps it, and a second tap is refused with humanHeld while a person uses the device

Every command is also an MCP tool. Point Claude Code or any MCP client at loupe mcp and it gets the same commands, with the same claims:

claude mcp add loupe -- loupe mcp

tap takes a node instead of a point: loupe tap <target> --text "Sign in" finds it in the accessibility tree and taps its center, and --id and --desc match the other fields. Two matches are refused with the candidates rather than guessed at. Coordinates still work, in device pixels, the ones ui reports in each node's center. sequence runs several steps in one call, and stops at the first that fails. Drive from the accessibility tree rather than from the video. boot starts a shut-down AVD or simulator, with --wait for how long to wait (0 returns at once), and boot-status reports on an AVD boot still running. docs/cli.md covers the commands, docs/mcp.md the tools, and docs/agent-api.md every HTTP route.

What it does

Android phones, Android emulators and iOS simulators feed one loupe binary; it streams to a browser and serves scripts and agents

Streams devices

  • Android phones over adb. One plugged in later appears in the picker; one unplugged stays listed as missing, with the reason.
  • Every installed AVD, booted or not. Opening one boots it from a warm snapshot. An idle emulator is paused after 5 minutes and shut down after 30. Save & Shut Down keeps what you installed for every later boot, Reset returns one to a clean state, and New device creates an AVD from the system images you have.
  • iOS simulators through simcap. Physical iPhones and iPads are a preview: they stream over a cable, and input is still being worked on. See docs/ios.md.
  • Devices on your other machines. Add another loupe server as a peer and its targets join your picker. See docs/remote-targets.md.

Feels like the device is in your hand

  • Video goes over WebTransport (HTTP/3), with WebSocket as a fallback. Adaptive bitrate lowers the encoder's rate when the link can't carry it and raises it again when the link recovers.
  • Multi-touch, swipes, hardware buttons, and your phone's own keyboard.
  • The clipboard works both ways, and can be shared across every open target and the Mac's pasteboard.
  • Add it to the Home Screen and it runs full screen as an app.

Lets agents work beside you

  • The accessibility tree with a precomputed center per node, tap by text, resource id or description, swipe, text, keys, waiting for a node, app launch, deep links, screenshots, APK install, logs, crash reports, boot and shutdown. On a debuggable Compose app, each node names the composable that drew it, with its source line.
  • camera points an AVD's, simulator's or iPhone's back camera at an image, so a scanner can be tested without holding a phone up to a screen.
  • Claims, the human hold and flags let you share a device with an agent. See Work on the same device as your agent.
  • Recording writes the encoder's output to an MP4, with no re-encode.

Fits into your workflow

  • A GitHub Action installs a pull request's APK on a target and comments on the PR with a link that opens it. See action/README.md.
  • Extensions are separate programs that loupe proxies under /api/ext, and they can draw overlays on a device. See docs/extensions.md.
  • loupe pair gives a device its own session, which you can revoke without re-keying every other device.

Security

Anyone who can reach the port can drive every device on it, so every request needs the shared token or a paired session, and plain HTTP is refused on anything but loopback. The token and every session have full access; there are no scopes yet. docs/security.md says what is protected and what isn't.

Build from source

git clone https://github.com/bmcreations/loupe && cd loupe
make build
./loupe -addr 127.0.0.1:8080 -synthetic -no-devices

Go is all it takes. The scrcpy-server jar is embedded and the web client has no build step, so there is no scrcpy to install and no npm. The test pattern needs ffmpeg; it should hold about 60 fps in the stats overlay before you plug in a device. docs/running.md lists every flag.

Docs

Doc For
getting-started.md From an install to a phone, a service and an agent
cli.md loupe <command>, claims between commands
mcp.md loupe mcp and pushing flags into Claude Code
agent-api.md Every /api/* route, claims and the human hold
targets.md AVDs, Android devices, the phone keyboard, the clipboard, device frames
ios.md iOS simulators, and physical iPhones in preview
running.md Every flag, the settings file, the stats overlay, tests
security.md The token, TLS, pairing and sessions

docs/README.md indexes the rest: architecture, the wire protocol, flags, recording, extensions and notes for working on the code.

Licensing

loupe is Apache 2.0. It embeds and redistributes the scrcpy-server jar, which is also Apache 2.0; third_party/scrcpy/LICENSE and THIRD_PARTY_NOTICES.md carry that text and the upstream attribution. Section 6 grants no trademark rights: nothing here may imply this is scrcpy or that Genymobile endorses it.

simcap, the iOS helper, is also Apache 2.0 and lives in its own repo, bmcreations/simcap. It calls private frameworks from your own Xcode install; docs/ios.md says which, and what that means for an Xcode update.

iPhone, iPad, Mac, macOS and Xcode are trademarks of Apple Inc. loupe is not affiliated with Apple.

About

Android devices, emulators and iOS simulators from your Mac, live in any browser at 60 fps, shared between you and your agents over a CLI, MCP or HTTP.

Topics

Resources

Security policy

Stars

12 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages