Pinky

Let any AI agent use your iPhone or Android phone, from macOS, Windows or Linux, with you in the loop.

Download · Get started · FAQ · Discord

English · 简体中文 · 日本語


A real Claude Code run on an Android 16 emulator. Pinky asks before payments by default; this run also asks before messages.

Pinky lets any agent (Claude Code, Claude Desktop, Codex, Cursor or a script) operate a real iPhone or Android phone over MCP, while you watch on your computer, approve risky steps, take over and review what happened. Approvals are enforced by Pinky's gateway, not by instructions to the agent.

  • Every platform. One app for macOS (Apple silicon and Intel), Windows and Linux. It drives Android phones (Android 10 to 17) and iPhones on iOS 17.4 or later: nothing to install on iOS 27 and later, and a helper installed once from Xcode on iOS 17.4 to 26, which you can also choose on iOS 27 (tried there and on Simulators, not yet on a phone below 27; details).
  • Tiny and native. The window is drawn by MyGo on the GPU, with no Electron and no webview: a 16–22 MB download that idles at about 70 MB of memory and 0% CPU on a Mac.
  • Any agent, one click. Settings › Agents connects Claude Code, Claude Desktop, Codex, Cursor and more, and any agent that can use MCP servers works, on the same computer or over HTTP.
  • Locked phone? Unlock it from your computer. Save the phone's PIN in Pinky once, then confirm each unlock with Touch ID, Windows Hello or your keyring's password. Agents never see the PIN.
  • Free and open source under the Apache-2.0 license, with no account to create.

You approve the risky steps. Payments, trades and transfers wait for your click; in Settings › Safety you can have sends, orders, deletions, calls, installs, links that leave the app and settings changes wait too, or every step. Pinky spots these buttons in 10 languages. The rules run in Pinky's gateway, so an agent can't approve itself, even when text on the screen tries to talk it into it.

Off-limits by default. Banking, wallet and password-manager apps are invisible to agents, and agents can't type into password or one-time-code fields. When an agent needs a banking or wallet app for a task, it asks, and you can allow that app for that task only. Every new agent needs your approval and gets only the scope you give it.

Your phone stays yours. On Android 13 and later, agents work on a hidden second screen, so the phone's own screen stays yours, or off and locked. On older Android phones and on iPhones they use the main screen.

Take over any time. Click the mirror and the agent pauses until you hand back; on Android, touching the phone yourself pauses it too. Stop all is ⌥⌘. (Ctrl+Alt+. on Windows and Linux) from anywhere.

Every run is on the record. Each step in plain words, screenshots and a screen recording with a mark per step, exportable as an HTML report. It all stays on your computer.

iPhones too. The same gateway, approvals and records work on iOS 17.4 and later (what works). Shown here on the iOS Simulator, with deletions set to ask.

Status: pre-alpha. Claude Code has used real phones through it end to end (an Android phone over USB and an iPhone on iOS 27), and agents can connect over stdio or HTTP. Unlocking from the computer, background work on Android, recordings, export, Wi-Fi pairing and the phone's files are built; some of it still waits for a person to try it. See docs/ACCEPTANCE.md for what works today and how to try it.

Get started

Install Pinky, connect your phone and add Pinky to your agent. Then ask the agent to do something on the phone, and watch it work in Pinky's window.

What you need

You need
MacmacOS 12 or later, with Apple silicon or Intel
WindowsWindows 10 or 11, 64-bit (x64)
LinuxA 64-bit PC (x86-64) with Ubuntu 20.04, Debian 11 or a newer system (glibc 2.29 or later), and GTK 3
Android phoneAndroid 10 to 17 and a USB cable. Pinky brings its own adb; on Windows some phones need a USB driver, and on Linux USB access (below)
iPhone or iPadiOS 17.4 or later, and a USB cable to set it up; afterwards it works over Wi-Fi too (below). Pinky prepares it itself, with Apple's developer disk image, which comes with Xcode or which Pinky can download from a third-party mirror when you ask (below). On iOS 17.4 to 26 also a helper app on the iPhone (below)
AgentAny agent that can use MCP servers, such as Claude Code, Claude Desktop, Codex or Cursor

1. Download and install Pinky

Get Pinky from the latest release:

  • Mac: download pinky-<version>-arm64.dmg for a Mac with Apple silicon (M1 or later) or pinky-<version>-amd64.dmg for an Intel Mac. Open it and drag Pinky to Applications. With Homebrew, brew install --cask diygod/tap/pinky does the same.
  • Windows: download pinky-setup-<version>-amd64.exe and run it. It installs Pinky for your account, without administrator rights. The installer is not signed yet, so SmartScreen may say that Windows protected your PC: choose More info, then Run anyway. To use Pinky without installing it, unzip pinky-<version>-windows-amd64.zip and open Pinky.exe.
  • Linux: on Debian and Ubuntu, download pinky_<version>_amd64.deb and install it with sudo apt install ./pinky_<version>_amd64.deb. On other systems, unpack pinky-<version>-linux-amd64.tar.gz into a folder of its own and run pinky in it.

Pinky looks for new versions by itself and, on a Mac and with the Windows installer, installs them too (Updates).

2. Connect your phone

Open Pinky and choose Add phone. A phone that is ready shows up in Pinky's window; when something is missing, the phone's page in Pinky says what.

Android

Add phone › Android shows these steps for your phone's brand, with its own menu names and extra switches: Xiaomi, OPPO, vivo, HONOR, HUAWEI, Samsung and Pixel, and general steps for the rest.

  1. On the phone, turn on USB debugging: in Settings › About phone, tap Build number 7 times, then turn on USB debugging in Settings › System › Developer options. Some brands name these menus a little differently.
  2. Plug the phone into the computer. When the phone asks whether to allow USB debugging, tap Allow. On Android 11 and later you can pair it over Wi-Fi instead, from Add phone (when it fails). Android 10 has no Wireless debugging: once it is plugged in, Use Wi-Fi instead… moves it to Wi-Fi (below).
  3. Pinky offers to install Pinky Companion, its app for the phone, which makes reading the screen many times faster and lets Pinky type in any language. The phone may ask you to allow the install once.

Each phone has a Checkup, in the ··· menu under its mirror, that lists what works and how to fix what doesn't, such as a Xiaomi's USB debugging (Security settings) switch.

Taking the phone out? With Tailscale, Pinky reaches it away from home too (how).


Add phone › Android, with a Xiaomi picked.

A Redmi's Checkup, with two things to fix.

Android tools

Pinky brings its own adb, the tool it reaches Android phones with, built from Android's source, so nothing else needs installing. When the computer has Android's platform tools already, from Android Studio, Homebrew or the system's packages, Pinky uses those, and shares their adb server with Android Studio and other tools.

USB on Windows and Linux

  • Windows: the phone's USB debugging needs a driver. Windows installs one by itself for many phones; when it has none, Pinky lists the phone as needing setup and says which driver to install: the Google USB Driver for Pixels, Samsung's for Samsung phones, the phone maker's for others. Unplug the phone and plug it in again afterwards.
  • Linux: the computer must let Pinky open the phone's USB device, which takes udev rules for Android phones: sudo apt install android-sdk-platform-tools-common on Debian and Ubuntu, android-udev on Arch, android-tools on Fedora. You may also need to be in the plugdev group. Then plug the phone in again. Pinky says so when they are missing.

When pairing over Wi-Fi fails

When a phone works on the cable but Pair over Wi-Fi does not finish, the pairing page says within half a minute what Pinky sees:

  • The phone hasn't shown up on the network yet: check that Wireless debugging is on and that the phone is on the same Wi-Fi as the computer. Guest Wi-Fi, routers with AP (client) isolation and many office networks keep devices from finding each other. There, choose Pair with a code instead: on the phone, tap Pair device with pairing code and enter the IP address and port and the six-digit code it shows, which change each time that dialog opens. Pinky then needs no search to pair; if it still cannot find the phone afterwards, it asks for the IP address and port at the top of Wireless debugging (not the pairing dialog's) and connects there. If it cannot reach the phone at those addresses either, the network keeps its devices apart: use a Wi-Fi where they can reach each other, such as your home network rather than its guest network, or the cable.
  • Pinky isn't allowed to look for phones on this network: on a Mac, Pinky needs Local Network access, and macOS gives no error without it: the search just finds nothing. Choose Open Local Network settings, turn on Pinky under System Settings › Privacy & Security › Local Network and try again (if macOS asks whether Pinky may find devices on your local network, click Allow). On a Mac, a phone's Checkup shows this too, under Local network. On Windows and Linux, a firewall can block the search the same way: let Pinky use the local network, or pair with a code.
  • Pinky can't look for phones on this network: check that the computer is connected to Wi-Fi or Ethernet.
  • The phone showed up, but pairing hasn't finished: if the phone shows an error or went back to Wireless debugging, scan the code again, or pair with a code.

When pairing stops with an error, the page says what adb reported:

  • The phone ended the pairing before it finished (QR code): the phone left its scanning screen, changed Wi-Fi, or something between it and the computer cut the connection; adb cannot tell which. Keep the phone on the scanning screen and try again, or choose Pair with a code instead next to the message.
  • The phone didn't accept the pairing (pairing code): a wrong code, or a port that is not the pairing dialog's. The address at the top of Wireless debugging is for connecting, not pairing, and adb answers the same way for both mistakes.
  • Nothing at that address is waiting to pair or The phone stopped waiting to pair: the pairing dialog or the scanning screen closed, or the port is wrong. Open it again and use what it shows now.
  • Couldn't reach the phone at that address or Pinky couldn't connect to it: the network keeps the computer and the phone apart, as above; a VPN or firewall on the computer can too.
  • The adb server running on this computer is too old: another program started an adb older than platform-tools 30. Quit it, or update it, and Pinky starts its own.

Pinky writes adb's own words to its log, which Help › Send Feedback… attaches with the diagnostics.

Pairing over Wi-Fi needs Android 11 or later; an Android 10 phone moves to Wi-Fi from the cable instead (Use Wi-Fi instead…, below). Up to Android 16, Wireless debugging turns itself off when the phone leaves the Wi-Fi network, even for another access point of it, or restarts: turn it on again, or pair again from Add phone.

iPhone

Pinky prepares an iPhone itself; Add phone › iPhone walks you through it.

  1. Plug the iPhone into the computer, unlock it, tap Trust and enter its passcode. On Windows, install Apple Devices from the Microsoft Store (or iTunes) first; on Linux, the usbmuxd package. Add phone says when they are missing.
  2. On the iPhone, turn on Developer Mode in Settings › Privacy & Security: Pinky makes the switch appear there. The iPhone restarts; unlock it, tap Turn On and enter the passcode.
  3. Pinky mounts Apple's developer disk image on the iPhone and lists it as ready. An iPhone on iOS 27 keeps the image when it restarts; below iOS 27 Pinky mounts it again after each restart, once you unlock the iPhone.

The developer disk image comes with Xcode, Apple's free app for developers, and Pinky does not ship it. On a Mac, install Xcode once and open it: Pinky uses the image it installs, and Xcode never has to run again. An iPhone on iOS 27 or later needs the image of Xcode 27 or later: Apple's signing server no longer signs older ones, and Add phone then says which image Pinky used and how to get a newer one. On Windows and Linux, copy /Library/Developer/DeveloperDiskImages/iOS_DDI from such a Mac into Pinky's folder (where). Without either, or when Apple refuses the image Pinky found (Xcode's, or one copied into Pinky's folder), Add phone offers to download the image from a third-party mirror, github.com/doronz88/DeveloperDiskImage (Xcode 27.0 beta 4, 32 MB, kept by the author of pymobiledevice3, not by Apple), only when you click Download; Pinky checks every file against the checksum it expects, and from then on uses it instead of an image Apple refused. On iOS 27 and later, no app gets installed on the iPhone.

Checked on the iPhone 13 mini (iOS 27.0.1): Pinky mounting Xcode's image itself (in about 1.5 s, after the image had been taken off), keeping the image already on the phone, and that the iPhone keeps the image when it restarts. Not yet tried on a phone: the downloaded image, the Developer Mode switch, iPhones below iOS 27, and iPhones on Windows. On Linux (Arch Linux), contributors have used an iPhone and an iPad on iOS 27.2 on the cable and over Wi-Fi, with the image already on them.

iPhones and iPads over Wi-Fi

Pinky also uses an iPhone or iPad over Wi-Fi while it is on the same Wi-Fi as the computer, and the computer lists it there, which it does once Wi-Fi connections are on for the phone. Pinky turns them on when you plug the phone in and it trusts the computer: it is the same setting as Finder's Show this iPhone when on Wi-Fi, so a phone already set up that way stays as it is. It is on by default; Settings › Phones › Use iPhones and iPads over Wi-Fi turns it off, which leaves the phones' setting alone. If a phone doesn't show up on Wi-Fi when you unplug it, its Checkup says where it stands under Wi-Fi: whether its Wi-Fi connection is on and whether Pinky turned it on, why Pinky couldn't, and whether this computer sees the phone on Wi-Fi.

  • An iPhone or iPad Pinky has used keeps working when you unplug it, as the same phone with its settings: Pinky moves it to Wi-Fi by itself, and back to the cable when you plug it in, and an agent's task goes on; its calls wait a few seconds meanwhile.
  • One Pinky has not used, such as a family member's iPad paired with this computer, shows as Found on Wi-Fi. Pinky reads its name, model and iOS version and does nothing else, and agents don't see it, until you choose Use, which sets it up over Wi-Fi, or Ignore, which keeps it off the list until you plug it in.
  • A locked iPhone or iPad on Wi-Fi shows as Locked on Wi-Fi, and Pinky connects to it once you unlock it: while it sleeps it drops off the network every minute or so, and connecting to it then lights its screen.
  • Setting one up over Wi-Fi: trusting the computer needs the cable, and so does making the Developer Mode switch appear while it is hidden (on a phone used with Xcode it shows already). Turning Developer Mode on happens on the phone, and Pinky mounts the developer disk image over Wi-Fi too, in about 9 s instead of 1.5 s. Add phone › iPhone says which step needs the cable.

Over Wi-Fi each step is slower than on the cable, screenshots most of all. Measured on an iPad Pro 11-inch (3rd generation, iPadOS 27.0.1), Wi-Fi against the cable: a swipe shows on screen after 80 to 210 ms (60 to 90 ms), the home screen reads in 0.6 to 2.6 s (0.5 to 0.6 s), a screenshot takes 5 s (1 s), and 0.2 % of the video's packets were lost (none). Unplugging moved a running task to Wi-Fi in about 5 s, and plugging in moved it back in 2 to 6 s (details).

On a Mac, the system's device service, usbmuxd, can lose an iPhone on Wi-Fi after its connection broke once (its Wi-Fi turned off and on, say), and not look for it again for up to about an hour; Finder loses it too. Pinky notices when a phone you use is on the network but no longer listed, shows it as Lost on Wi-Fi, and offers Restart device service… on its page: after you confirm, macOS asks for an administrator's password, and every iPhone and iPad, also on a cable, disconnects for a second or two. sudo killall usbmuxd in Terminal does the same. Right after you unplug a phone it says so within about 10 seconds; it waits a minute otherwise, as a phone that wakes comes back by itself. A phone you unplug that this computer doesn't see on Wi-Fi at all shows as Not seen on Wi-Fi, with what may hide it: it's asleep, on another network or one that keeps devices apart (guest networks, some routers), a VPN, or Pinky not allowed on the local network.

On Linux, the system's device service (the usbmuxd package) lists iPhones and iPads only on the cable, so Pinky looks for them on Wi-Fi itself: it finds the ones paired with this computer on the network and connects to them directly. There is nothing to install or set up for it beyond usbmuxd. If you run a device service that lists phones on Wi-Fi itself, such as netmuxd, and start Pinky with USBMUXD_SOCKET_ADDRESS pointing at it, Pinky uses that instead.

While Pinky opens a phone, or moves it between the cable and Wi-Fi, it shows Connecting or Moving to Wi-Fi rather than offline. Over Wi-Fi Pinky reads text from the live picture rather than from screenshots, which take about 5 s there. An iPhone or iPad without a passcode never reads as locked, so after it has dropped off the network to sleep, Pinky connects to it only once it has been back for 30 seconds.

iPhones on iOS 17.4 to 26

Below iOS 27, an iPhone takes taps and typing from a computer only through a helper app on the phone: WebDriverAgent, which you build and install once from Xcode with your Apple ID (how). With a free Apple ID it has to be installed again every 7 days: two days before, the phone's page and its checkup remind you, and once it has run out the phone shows as needing setup and says why (how to install it again). It has not been tried on an iPhone below iOS 27 yet. Without it, Pinky can only show and read the screen (on a Mac) and open apps: no taps, swipes or typing. iOS 17.3 and earlier are not supported.

3. Add Pinky to your agent

In Pinky, open Settings › Agents and click Connect next to your agent. Pinky finds Claude Code, Claude Desktop, Codex, Cursor, VS Code, Copilot CLI, Windsurf (Devin Desktop) and Gemini CLI on your computer and adds itself to the agent's MCP servers, by the app's own path: with the agent's own command where it has one, such as claude mcp add, or in its settings file, which Pinky copies first and changes only in Pinky's entry. It also installs Pinky's agent guide, SKILL.md, where the agent reads skills. Until an agent is connected, a card in Pinky's sidebar offers to do it, or says where to get one.

  • Claude Desktop: Connect opens Pinky's extension in Claude Desktop; click Install there. Double-clicking pinky-<version>.mcpb from the release page does the same.

  • Other agents: Settings › Agents › Add an agent by hand shows the command for your copy of Pinky, with buttons that copy it. Add an MCP server (stdio) that runs it. In a JSON config, with the Homebrew cask or a Linux package:

    { "mcpServers": { "pinky": { "command": "pinkyctl", "args": ["mcp"] } } }

    Claude Code in a terminal: claude mcp add --scope user pinky -- pinkyctl mcp. Most agents read the guide from ~/.agents/skills/pinky/SKILL.md, Claude Code from ~/.claude/skills/pinky/SKILL.md.

The command is pinkyctl, not pinky: many computers already have another program named pinky. An agent on another computer or in a container can connect over HTTP instead (how). docs/mcp.md says what Connect changes for each agent.

4. Try it

Ask the agent to do something on your phone, for example "Open Messages on my phone and tell Sam I'm running late." The first time an agent connects, Pinky asks whether to allow it and what it may do. Payments wait for your click in Pinky's window; in Settings › Safety you can have sends, deletions and more wait too.

No phone at hand? Quit Pinky and start it with two scripted demo phones (a payment to approve, a blocked banking app, a password field): /Applications/Pinky.app/Contents/MacOS/Pinky --fake on a Mac, pinkyctl --fake on Linux, or & "$env:LOCALAPPDATA\Programs\Pinky\Pinky.exe" --fake in PowerShell on Windows.

Using Pinky

Phones

  • Android: connected over USB or Wi-Fi (above). Pinky works over adb and a bundled scrcpy server. Its companion app, which ships with Pinky, reads the screen in about 70 ms instead of 2 s and types any language without the clipboard: the phone's page offers to install it (the phone may ask you to allow it once). Its accessibility service is on only while an agent works on the phone, as banking apps refuse to run next to one (why). On Android 13 and later, agents work on a background display, so the phone's own screen can stay off and locked. Text that an app draws without describing it to the accessibility tree, as in mini-programs and other web pages inside super-apps, games and maps, is read from the screen's pixels (OCR) on macOS and Windows, so agents can read it and tap it. Pinky reads a blocked app this way only once you allow it for the task, never a locked phone, and keeps no picture.

  • Wi-Fi on Android 10: Android 10 has no Wireless debugging. Plug the phone in and choose Use Wi-Fi instead… in the ⋯ menu under its picture (or in Settings › Phones): Pinky has the phone's adb listen on the network (adb tcpip, port 5555), connects to it at its Wi-Fi address and says when you can unplug it. It connects again by itself when the phone is back on the network, also at a new address. While it is on, any computer on the same network can try to connect to the phone: if the phone asks Allow USB debugging? when you are not connecting it yourself, tap Cancel, and use it only on Wi-Fi you trust. It lasts until the phone restarts; then plug it in once and choose Use Wi-Fi again. Stop the Wi-Fi connection in the same menu turns it off (details).

  • iPhone: connected over USB or Wi-Fi (above) and prepared by Pinky (above); iPads work the same way. What Pinky can do depends on the iOS version and on how Pinky connects, which you can choose for each iPhone in Settings › Phones (Automatic picks by version, as below):

    iOSHowWhat worksTested on
    27 and laterXcode's Device Hub protocol; nothing installed on the phoneEverything. Typing pastes the text and puts your clipboard backiPhone 13 mini, iOS 27.0.1
    17.4 and later, with the helperThe WebDriverAgent helper, installed once from Xcode (how): automatic on iOS 17.4 to 26, your choice on 27Everything, and the phone shares no screen, so banking apps that refuse screen sharing keep working (DBS digibank and China Merchants Bank in testing). Slower than Device Hub: a home screen reads in about 7 s instead of under 0.5 s, a tap takes 0.5 to 0.8 s. Now and then iOS asks for the passcode on the phone before the helper starts. The live picture needs macOSiPhone 13 mini, iOS 27.0.1, with the helper chosen; iOS 18.5 and 26.5 Simulators. Not yet on a phone below iOS 27
    17.4 to 26, without itThe developer services alone; nothing installedWatching (a few frames a second, macOS only), reading the screen (placed by OCR, macOS only) and opening apps. No tapping, swiping, typing or Home: the phone offers no input without the helperThe same services on iOS 27.0.1; not yet on a phone below iOS 27
    17.3 and earlierNot supported: before 17.4 the connection needs administrator rights, and iOS 16 and earlier need a developer disk image that current Xcode no longer includes

    The helper is Appium's WebDriverAgent, signed with your own Apple ID. The signature lasts 7 days with a free Apple ID and a year with a paid developer account. Pinky reads on the iPhone when it runs out: two days before, the phone's page and its checkup remind you to install the helper again from Xcode, and once it has run out the phone shows as needing setup and says why, instead of failing to start the helper (how).

  • Screen sharing on iPhone: while Pinky streams an iPhone's screen, iOS tells apps that the screen is being shared, and some banking apps (DBS digibank and China Merchants Bank among them) refuse to run or warn you. Pinky streams it while the phone's page or tile is open in Pinky, while an agent works on it, and for 30 seconds after; then such apps work again. Over CoreDevice, agents cannot use them. Connect that iPhone through the WebDriverAgent helper instead (Settings › Phones): the phone then shares no screen, and agents can use those apps too.

  • Locked phones: Pinky never keeps a phone awake. It wakes the screen before a step; save the phone's PIN in Settings › Phones to unlock it from the computer with Touch ID. Agents never see the PIN. On Android this is checked on AOSP-style lock screens (LineageOS on a Mi 10 Pro, the Android 10, 16 and 17 emulators); the lock screens of Xiaomi, Samsung, OPPO, OnePlus, vivo, Honor and Huawei are only covered by tests made from what is known of them, and where Pinky cannot read the PIN pad with confidence it enters nothing (details).

  • Files: on Android, agents copy files between the phone's Pinky folder (/sdcard/Pinky, the only place on the phone they may reach) and a folder on the computer, and copying to the phone asks you first. Pictures copied there show in the phone's gallery and photo pickers, so an agent can attach them in a chat app. An agent on another computer cannot reach that folder, so it sends Pinky the file first: small files in the call, larger ones to a one-time link Pinky gives it. Copying the file to the phone then asks you as usual (details). Not on iPhones.

  • Removing a phone: Remove this phone… in the phone's ⋯ menu (also on its page while it is offline, on its tile in All phones, in its right-click menu in the sidebar and in Settings › Phones) takes it off the list and deletes its saved PIN and its settings. Its tasks, screenshots and recordings stay in Activity unless you tick the box to delete them too, and a task running on it stops. A phone on a cable comes back at once, as a new phone, until you unplug it. A phone on Wi-Fi is disconnected and stays off the list, even when adb connects it again by itself; to add it back, pair it again in Add phone or plug it in. An iPhone or iPad on Wi-Fi stays off the list until you plug it in. Pinky does not unpair the phone from your computer: its USB or wireless debugging pairing, or the iPhone's trust, stays for other apps (details).

Phones away from home

An Android phone does not have to be on the computer's network. With Tailscale on the computer and on the phone, signed in to the same account, Pinky reaches the phone through it: leave the computer at home and take the phone out, on mobile data or another Wi-Fi. Android runs one VPN at a time, so keep other VPN and proxy apps off on the phone: they turn Tailscale off.

  1. Set the phone up once while it is near the computer, by cable or on the same Wi-Fi: Settings › Phones › Use away from home › Turn on…. Add phone › Android › Phone not on this network? Use Tailscale walks you through Tailscale on both sides and lists the phones on your tailnet.
  2. Pinky has the phone's adb listen on the network (adb tcpip, port 5555) and connects to the phone at its Tailscale address. It uses that connection whenever the phone has no connection on the computer's network, so the phone stays in the list as you leave.
  3. The phone's adb then takes connections on every network the phone joins, from the computers it already trusts; any other computer makes the phone ask. Only the way through Tailscale is encrypted. It lasts until the phone restarts, and Turn off stops it at once. Pinky only reads Tailscale's status and never changes its settings.
  4. Keep this computer awake for phones away (Settings › Phones, on by default) stops the computer's idle sleep while a phone is connected through Tailscale. A MacBook still sleeps when its lid closes.

At home, Tailscale is as fast as Wi-Fi; away, the phone's upload carries the picture, so Pinky streams lighter through Tailscale (1 Mbit/s), and on a weak 4G hotspot each step takes seconds. Details, measurements, data use and what to do when it does not connect: docs/away-from-home.md. An agent can be away from the computer too: Remote agents.

Updates

Pinky looks for a new version at launch and every few hours, and shows a card with what changed, Update now and Later. With Settings › Advanced › Update automatically (on by default) it installs it by itself once no agent is working and nobody has used Pinky for ten minutes, and it updates Pinky Companion on Android phones that are free; its accessibility service stays off until the next task. A Pinky Companion signed with the public key that its builds had until 8 November 2026 is uninstalled and installed again, signed with Pinky's private key, and Pinky tells you; on a phone that asks before installing apps over USB, the phone's page says why and waits for your Update. After an update, What's new lists the changes since the version you had (from CHANGELOG.md, or its Chinese version, CHANGELOG.zh-CN.md, when Pinky is in Chinese).

  • macOS: Pinky.app replaces itself after checking the download's checksum, that it is signed by Pinky's developer and that Apple notarized it, and goes back to the old version if the new one does not start. The Homebrew cask's copy updates itself the same way, and brew upgrade leaves it alone while it is current. A copy run from the disk image or from a folder you cannot write to says how to update it instead.
  • Windows: a Pinky that its installer installed runs the new installer quietly, after checking its checksum, starts the new version and goes back to the old one if that does not start. The portable copy downloads the installer for you.
  • Linux: Pinky downloads the release for you to install.
  • Terminal: pinkyctl update installs an update while Pinky is not running; pinkyctl daemon only logs that one is out.

Details: docs/notes/updates.md.

Usage statistics, crash reports and feedback

Pinky shares anonymous usage statistics (counters such as tasks run, tools called and phones connected, about once a day, with a random install id) and crash reports; turn both off in Settings › Privacy or with DO_NOT_TRACK=1. Screens, typed text, app names, phone names and ids, PINs and file names are never sent. Help › Send Feedback… opens a GitHub issue with your message and diagnostics filled in, which you read and submit yourself. docs/TELEMETRY.md lists everything.

FAQ

Which agents work with Pinky?

Any agent that can use MCP servers: over stdio, by running pinkyctl mcp, or over HTTP with an agent token (how). Settings › Agents connects Claude Code, Claude Desktop, Codex, Cursor and other agents it finds on your computer in one click. Claude Code is the one that has used real phones end to end so far. Pinky brings no model of its own: your agent does the thinking.

Can an agent approve its own risky step, or be talked into it?

No. The rules run in Pinky's gateway, between the agent and the phone. A step that needs you comes back to the agent as approval_pending, and nothing happens on the phone until you click Allow in Pinky; the agent has nothing it could send to confirm it. Before acting, Pinky checks that the button is still where it was, and no answer within 60 seconds means no. Pinky finds these buttons by their labels in 10 languages, so an unusual one could slip through: for more control, Settings › Safety has Ask before every action and Read-only mode.

What can't agents see?

Banking, wallet and password-manager apps, from a list that comes with Pinky and that you can add to in Settings › Safety, where you pick the app from those on your phones: agents get no screen from them, and their notifications are hidden, in the notification shade and on the lock screen too. Where another screen shows a blocked app, as its notification in the shade or in a banner, or its card in recent apps, the agent reads only that something is hidden there, and the screenshots it gets, and those in Activity, cover it with a gray box (screen recordings, which stay on your computer, show it as it was). Agents can't type into password or one-time-code fields. When an agent needs a banking or wallet app for a task, Pinky asks you first. If you allow it, the agent may open and read that app for the rest of the task, what your rules ask about there still asks, and Pinky keeps no screenshots or recordings of it: to read text that only its pixels show, Pinky looks at its screen in memory and gives the agent the text, never the picture. Password managers are never offered.

One-time codes are masked before an agent reads them: in a text message, an email, a notification or anywhere else on the screen, "Your code is 482913" reaches the agent as "Your code is ••••••", and the screenshots it gets, and those in Activity, have the code covered with a gray box. Prices, phone numbers, dates and numbers in text that is not about a code stay as they are. Screen recordings, which stay on your computer and never go to agents, show codes as they were. You can turn this off in Settings › Safety › Hide codes from agents.

Does my phone's screen go to the cloud?

Not through Pinky. Screenshots, recordings and history stay on your computer, for 30 days unless you change it in Settings › Privacy, where you can also delete them. What the agent reads goes to the agent you chose, as with any tool you give it. Pinky's anonymous usage statistics never include screens, typed text or app names (above).

What does Pinky install on my phone?

On Android, Pinky Companion, when you click Install; Pinky keeps it up to date and turns its accessibility service on only while an agent works (why). On an iPhone, no app on iOS 27 and later: Pinky mounts Apple's developer disk image, as Xcode does. On iOS 17.4 to 26, the WebDriverAgent helper, which you install once from Xcode (how).

Will banking or other apps notice Pinky Companion?

While its accessibility service is on, they can. Malware abuses accessibility services, so many banking apps refuse to sign in while an app from outside an app store has one turned on: in Malaysia (Maybank, CIMB, HSBC and the other members of the Association of Banks in Malaysia, since 2024) and in Singapore (DBS, OCBC and UOB, since 2023) among others. Pinky Companion is such an app, as Pinky installs it over USB. Apps such as WeChat, Douyin and Xiaohongshu can see the service too and watch for automated use; we know of no report that they flagged Pinky Companion, but letting an agent use them may be against their terms.

Apps can also see that USB debugging or Wireless debugging is on, which Pinky needs on every Android phone; some apps, banking apps among them, warn you or refuse to run while it is. It stays on for as long as you use the phone with Pinky.

So Pinky turns the service on only while an agent works on the phone: as a task starts, and off again a few seconds after the task ends or you take over the phone, or a minute after the agent's last step. The rest of the time it is off, and those apps work as usual. While an agent works, even on the phone's background display, they see it: to use one of them then, click Take over in Pinky first, or end the task.

To keep Pinky from turning the service on at all, uninstall Pinky Companion on the phone (Android's Settings › Apps). Pinky works without it, only more slowly: it reads a screen in about 2 s instead of 70 ms, and types text other than plain English through the phone's clipboard. Not now on the phone's page puts away Pinky's offer to install it again.

How is Pinky different from other phone tools for agents?

We looked at more than a dozen before building it. None of the open-source ones covers iPhone and Android, runs on macOS, Windows and Linux, works with any agent and keeps a person in the loop, all at once. Most leave it to the agent to ask first, or block whole kinds of actions; Pinky holds the one risky tap itself, outside the agent, and records every run.

Is it safe to give my phone to an agent that can run commands?

An agent that can run commands as you could reach the phone without Pinky, through adb for example, and skip its rules. Run such agents in a sandbox without access to the phone, or plug the phone into another computer and let the agent connect to Pinky there over HTTP (how).

Build from source

To use Pinky, install a release (Get started). Building it yourself, to work on it, needs Go 1.27.3 or later, and on a Mac Xcode's command line tools.

Pinky is one Go binary without cgo; MyGo (go tool mygo build) packages it for each system. The live mirror and recordings use FFmpeg 9's shared libraries, which Pinky loads at run time: from PINKY_FFMPEG_DIR, from the app (macOS), next to the executable, then from where the system keeps libraries. Every release carries its own minimal LGPL build (scripts/ffmpeg.sh, the H.264 and HEVC decoders): in Pinky.app, and next to the executable in the Windows installer and zip and in the Linux .tar.gz and .deb (docs/RELEASING.md). A build of your own needs one too: make app adds it to Pinky.app, and scripts/release.sh build makes every package with it. Without FFmpeg everything but the mirror works, and Pinky says what is missing.

macOS

make companion   # optional: the Android companion APK (Android SDK and JDK)
make app         # build/pinky/darwin-<arch>/Pinky.app and pinky-<version>-<arch>.dmg

make app builds a minimal LGPL FFmpeg 9 from source the first time (make ffmpeg, about a minute: the H.264 and HEVC decoders with VideoToolbox), puts it in Pinky.app/Contents/Frameworks, with CMake installed (brew install cmake) also builds Pinky's own adb (make adb) into Contents/Helpers, adds the companion APK when it is built (COMPANION_APK=path picks another), signs the app and makes the .dmg from the finished app. Install from the .dmg by dragging Pinky to Applications. The app is signed ad hoc unless macos.signingIdentity in cmd/pinky/mygo.json (or make app MACOS_SIGN=…) names a Developer ID; an ad-hoc signed app runs on the Mac that built it, and another Mac's Gatekeeper refuses it. make app does not notarize. make release signs with the Developer ID in RELEASE_SIGN and notarizes the .dmg (make notarize: submit, wait, staple), with the notarytool profile in NOTARY_PROFILE (pinky-notary), which you store once with xcrun notarytool store-credentials pinky-notary --apple-id <Apple ID> --team-id <team>. Releases themselves are built, signed and published by a workflow for both kinds of Mac, Windows and Linux; see docs/RELEASING.md.

To try your build, open it (open build/pinky/darwin-arm64/Pinky.app) and connect your agent to it with Connect in its Settings › Agents, which uses this build's path, or for Claude Code from the checkout:

claude mcp add --scope user pinky -- "$PWD/build/pinky/darwin-arm64/Pinky.app/Contents/MacOS/Pinky" mcp
mkdir -p ~/.claude/skills/pinky && cp docs/SKILL.md ~/.claude/skills/pinky/SKILL.md

go run ./cmd/pinky does not see the app's FFmpeg: install FFmpeg 9 with Homebrew (brew install ffmpeg) or point at the build, PINKY_FFMPEG_DIR=build/ffmpeg/lib go run ./cmd/pinky.

Unlocking a phone from the computer keeps its PIN in the login keychain and asks for Touch ID or the Mac's password each time.

Windows

go tool mygo build -platform windows/amd64 cmd/pinky   # build/pinky/windows-amd64/Pinky.exe (and an installer where NSIS is installed)
go build -o pinky.exe ./cmd/pinky                      # a console build, for pinky devices and other commands in a terminal

Pinky.exe is a windowed program: agents that start Pinky.exe mcp talk to it over pipes, but a terminal shows nothing it prints, so use the console build there. A release's installer and zip carry FFmpeg next to Pinky.exe (with D3D11VA). For a build of your own, scripts/ffmpeg.sh build/ffmpeg-windows windows-amd64 makes the DLLs in build/ffmpeg-windows/bin (in a Docker container); put them next to the executable, or set PINKY_FFMPEG_DIR to their folder (the ffmpeg-n9.0-…-win64-lgpl-shared builds at FFmpeg-Builds work too). A build of your own carries no adb, so Android phones need the one of Android's platform tools; scripts/adb.sh build/adb-windows windows-amd64 builds Pinky's own (in a Docker container), whose adb.exe and two DLLs go next to the executable. iPhones are untested on Windows. PINs are kept in the Credential Manager, and each unlock asks through Windows Hello, or for the account's password where Hello is not set up.

Linux

go tool mygo build -platform linux/amd64 cmd/pinky   # build/pinky/linux-amd64/: pinky, a .deb, a .tar.gz with install.sh, a PKGBUILD

The window needs GTK 3 and EGL (libgtk-3-0, libegl1; Mesa draws it in software where there is no GPU). A release's .tar.gz and .deb carry FFmpeg next to pinky; it needs glibc 2.29 or later (Ubuntu 20.04, Debian 11 and newer) and decodes in software. For a build of your own, scripts/ffmpeg.sh build/ffmpeg-linux linux-amd64 makes the libraries in build/ffmpeg-linux/lib (in a Docker container); put them next to the executable, or set PINKY_FFMPEG_DIR to their folder. For hardware decoding (VA-API), point PINKY_FFMPEG_DIR at an FFmpeg 9 that has it, such as the distribution's or FFmpeg-Builds' shared builds (which need libva2 and libva-drm2); Pinky looks there first. iPhones are untested on Linux. PINs are kept in the Secret Service (GNOME Keyring, KWallet, KeePassXC) in a keyring of Pinky's own, which the first save asks you to give a password and which Pinky locks again after each use, so every unlock asks for that password.

Build and test

make check          # build (CGO_ENABLED=0), vet, test
make app            # Pinky.app with FFmpeg and the companion, and a .dmg (macOS)
make ffmpeg         # FFmpeg 9 for Pinky.app, in build/ffmpeg
make adb            # Pinky's own adb for Pinky.app, in build/adb (needs CMake)
make companion      # the Android companion APK (Android SDK and JDK needed)
make e2e            # a binary with MyGo's automation socket, for UI checks
scripts/smoke.sh    # the fake gateway, pinky devices and a task through pinky mcp
make dist           # a dry run of a release, in dist/<version>/ (docs/RELEASING.md)

go run ./cmd/pinky --fake runs the app with two scripted phones (a payment to approve, a blocked banking app, a password field), so it needs no phone.

Tests that need a real phone use the device build tag; see docs/WORKING.md. go run ./scripts/secretcheck checks by hand that unlocking asks you (Touch ID, Windows Hello). PINKY_FFMPEG_APP=build/pinky/darwin-arm64/Pinky.app go test -run TestPackagedFFmpeg ./internal/video/ checks that the app decodes with its own FFmpeg; given the folder of an unpacked Windows or Linux package, it checks that package's.

CI (.github/workflows/ci.yml) builds, vets and tests on Linux and Windows, builds and vets on macOS, runs scripts/smoke.sh on all three, packages for Linux and Windows, and on Linux opens the window under Xvfb and captures it through the automation socket. It runs for main, pull requests, by hand, and the platform session's claude/platform-* branches.

Code layout

cmd/pinky/                    app, daemon and MCP shim in one binary
internal/screen/              the screen format agents read
internal/driver/              driver interfaces; android/ and ios/ implement them
internal/gateway/             sessions, leases, the action pipeline, the client API
internal/policy/, approval/   rules and approvals
internal/history/             task history (SQLite)
internal/mcp/                 the MCP server
internal/api/                 the local socket for agents and clients
internal/demo/                scripted fake phones
internal/update/              new versions: the feed, checks, the swap, What's new
internal/video/, ui/          the desktop client (MyGo native UI, FFmpeg decoding)
internal/telemetry/           usage statistics, crash reports and feedback
worker/                       the Cloudflare Worker that receives usage statistics and crash reports
android/companion/            the Android companion app (Kotlin)
scripts/                      device locks and an MCP call script for checks
docs/                         design, agent guide, MCP reference and notes

Documents

Community

Ask questions, share what your agent does on your phone and follow development on Discord. Bugs and feature requests are welcome as GitHub issues; Help › Send Feedback… in Pinky opens one with diagnostics filled in.

License

Apache-2.0