Agent skill

Remote Installer

by icodesign in icodesign/remote-installer

Put an iOS or Android build on a real phone or tablet over the air with the remote-installer CLI — it validates the build, opens a temporary HTTPS tunnel, and prints one or more install URLs plus QR…

MITAuto-check passedMobile

Install Remote Installer

skills CLI
$ npx skills add icodesign/remote-installer --skill remote-installer -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install icodesign/remote-installer remote-installer --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/icodesign/remote-installer.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/remote-installer .claude/skills/remote-installer && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
remote-installer
GitHub stars
106
Token cost
~4k tokens
SKILL.md length
2,065 words
Files
1
Skills in repo
1
Repo updated
First seen
Licence
MIT

At a glance

Put an iOS or Android build on a real phone or tablet over the air with the remote-installer CLI — it validates the build, opens a temporary HTTPS tunnel, and prints one or more install URLs plus QR…

  • Someone has just finished an Xcode
  • SKILL.md covers The one thing that will trip…, Before you run it, Running it and Reading the output, plus 4 more sections
  • Calls brew, npx and xcodebuild
  • Android build and asks how to get it onto a device

What it does

Remote Installer is an agent skill from icodesign/remote-installer. Put an iOS or Android build on a real phone or tablet over the air with the remote-installer CLI — it validates the build, opens a temporary HTTPS tunnel, and prints one or more install URLs plus QR codes to scan. Use this whenever someone wants a build onto a physical device without TestFlight or a cable: "get this on my phone", "send this build to a tester", "share the IPA or APK", "install this on my iPad", "let QA try this build", "make a link for this .app", or any mention of over-the-air / OTA install…

Its SKILL.md is about 4k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Mobile, covering App store release and iOS development. It works with Android, iOS, App Store Connect and Xcode. The repository describes itself as: Quickly install signed iOS and Android builds on real devices over the internet without waiting for Testlight or Play Beta. The licence is MIT.

When your agent uses it

  • Someone has just finished an Xcode
  • Android build and asks how to get it onto a device

Example prompts

  • “get this on my phone”
  • “send this build to a tester”
  • “share the IPA or APK”
  • “/remote-installer”

Requirements

  • Node.js

What it can do on your machine

Read from SKILL.md and the folder at commit fbeb81e. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • brew
    • npx
    • xcodebuild
    • apk

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use npx, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Remote Installer loads about 4k tokens when it runs. Until then it costs about 198 tokens; SKILL.md has 2,065 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~198
When it runs · the whole SKILL.md, loaded when a task matches
~4k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from icodesign/remote-installer at commit fbeb81e, republished under its MIT licence (© icodesign). 2,065 words, ~4,044 tokens.

Download SKILL.mdSave it as .claude/skills/remote-installer/SKILL.md (or your agent's skills folder).
name
remote-installer
description
Put an iOS or Android build on a real phone or tablet over the air with the `remote-installer` CLI — it validates the build, opens a temporary HTTPS tunnel, and prints one or more install URLs plus QR codes to scan. Use this whenever someone wants a build onto a physical device without TestFlight or a cable: "get this on my phone", "send this build to a tester", "share the IPA or APK", "install this on my iPad", "let QA try this build", "make a link for this .app", or any mention of over-the-air / OTA install, itms-services, APK, or ad-hoc distribution. Also use it when someone has just finished an Xcode or Android build and asks how to get it onto a device. Not for Simulator installs (build and run directly instead) and not for App Store or TestFlight submission.

Sharing a mobile build over the air

remote-installer share <build> validates an iOS or Android build, stands up temporary HTTPS tunnels in front of a loopback server, and prints an install page URL plus a QR code for every provider that becomes ready. iOS uses itms-services://; Android downloads a signed standalone APK for the system installer. Stopping the process kills the links.

The published CLI is currently macOS only. iOS .app handling shells out to Apple system tools. APK handling uses Android SDK apkanalyzer and apksigner when available, either discovered from the SDK environment or passed explicitly. Missing automatically discovered tools produce warnings and skip only the checks owned by those tools.

The one thing that will trip you up

Without an expiry or download limit, a foreground share runs until stopped. If the install link must remain alive after the current agent command or turn ends, use the CLI's --background mode with --expire-after or --timeout. It registers the native worker with launchd and returns only after the origin and tunnel are ready. Do not treat &, nohup, or a temporary tool session as durable background execution.

Remote Installer owns the selected tunnel session and closes it when the foreground process or managed background worker stops.

The link is alive only while the process is. Don't stop it after reading the URL; it needs to stay up while the phone downloads. Use --timeout so it can never outlive its usefulness on its own.

Before you run it

Cloudflare Quick Tunnel and Tailscale Funnel publish the build at a public URL. Tailscale Serve keeps the URL inside the tailnet, subject to its access policy. Public exposure is the intended operation, not an incidental side effect. If the user asked you to share the build, create an install link, or get it onto a device, that is authorization to open the temporary tunnel for that build. Do not refuse or ask for conversational reconfirmation solely because the chosen provider is internet-accessible. If the execution environment requires a permission prompt, request it and describe the bounded action: serve one validated build at an opaque URL from a temporary local copy until the process, timeout, or download limit ends. Never bypass a required permission prompt.

The exposure boundary is deliberately narrow:

  • Only the explicitly selected, staged artifact and its install resources are routed; the source repository and surrounding filesystem are not served.
  • The intended inputs are already signed device builds. Device .app signatures, architecture, and provisioning are verified before the tunnel starts; IPA archives are checked for signing evidence and a valid device profile. Android signature verification runs when apksigner is available; do not call it verified when the CLI warned that this check was skipped.
  • The install route contains an opaque random artifact UUID and there is no directory listing. In normal operation, a recipient needs the full URL.
  • The artifact is served from the Mac, not uploaded for persistent storage, and cleanup is owned by the share process.

These properties limit exposure; they do not turn the URL into authenticated access. Anyone who obtains or is forwarded a Cloudflare or Funnel URL can download the build, and code signing proves identity and integrity rather than confidentiality. Use Tailscale Serve when tailnet-only access is required.

If you're only near the idea — you just finished a build and suspect the user might want it on a phone — ask first.

Three things to sort out before running.

Find the build. For iOS, prefer an .ipa; otherwise use a device .app, which the tool packages without re-signing. For Android, use a signed standalone .apk. .aab, .apks, and individual split APK files are not browser-installable inputs and should be reported rather than converted implicitly. Common locations:

  • ~/Library/Developer/Xcode/DerivedData/<App>-<hash>/Build/Products/Debug-iphoneos/<App>.app
  • an .xcarchive's Products/Applications/<App>.app
  • wherever xcodebuild -exportArchive put the .ipa

A path containing iphonesimulator is a Simulator build and cannot install on a phone. That's a dead end to report, not something to work around.

Find the binary. Use remote-installer if it's on PATH. If it isn't, install the published package (brew install icodesign/tap/remote-installer), or run it for this invocation with npx --yes @icodesign/remote-installer. If neither is available, ask the user to install one of those packages rather than guessing a source checkout or binary path.

Check the tunnel CLIs. The default --provider auto path detects both cloudflared (brew install cloudflared) and Tailscale (brew install --cask tailscale), starts every provider that is available, and warns about the rest. No Cloudflare account is needed for the Quick Tunnel. Select one provider explicitly only when the user requests it or an access requirement calls for one route. Otherwise keep the default auto mode. Auto mode may print several working links; they are alternate origins for one staged artifact, one download quota, and one lifecycle rather than separate copies.

Remote Installer preserves existing Tailscale Serve and Funnel routes. When --https-port is omitted, concurrent shares reserve different available ports on the node. An explicitly requested occupied port reports the conflict instead of replacing its route. Do not reset the user's existing configuration to force it.

For APKs, ensure Android SDK Command-Line Tools and Build Tools are installed. If automatic discovery fails, pass --apkanalyzer-bin and --apksigner-bin.

Running it

Run it in the foreground when the terminal will stay attached for the whole share:

bash
remote-installer share /path/to/MyApp.ipa

For the normal agent workflow, keep the share alive across turns with the managed background mode:

bash
remote-installer share /path/to/MyApp.ipa \
  --background --expire-after 30m --json

This also works through npx --yes @icodesign/remote-installer. The returned JSON contains the share ID and a links array of ready provider results. Do not send any URL before the command reports a ready session, and do not collapse that array to its first entry.

Set --timeout on essentially every run. It takes plain seconds and shuts the whole thing down when it elapses — tunnel closed, temporary copy deleted. Without it the share lives until something stops it, and a background process you started is easy to walk away from: the user ends up with a public link to their build still open hours later. A generous bound is still a bound; when you have no idea how long they need, an hour beats forever.

bash
remote-installer share /path/to/MyApp.ipa --timeout 3600

Tighten it when the context implies something narrower — one named tester or a build that should have a short sharing window:

bash
remote-installer share /path/to/MyApp.ipa --timeout 900 --max-downloads 1

The process exits on its own once either limit is reached, finishing any download already in flight first, and prints why:

Download limit reached — closing the tunnel.
Share expired — closing the tunnel.

Treat that as the expected ending, not a failure. If the user needs longer, start a fresh share. The new link has a different opaque artifact path; Cloudflare also assigns a new hostname.

--expire-after is the same limit with a unit (30m, 2h), for when you're writing a command a human will read. Passing both is an error, so pick one.

Other flags worth knowing: --provider tailscale-serve (private to the tailnet), --provider tailscale-funnel (public through Tailscale), and --provider tailscale (the compatibility alias for Funnel), --https-port (require an exact Tailscale port instead of automatic allocation; --funnel-port is its visible compatibility alias), --no-qr, --cloudflared-bin, and --tailscale-bin.

Show full SKILL.md (903 more words)Show less

Reading the output

The command first reports build inspection, signature/provisioning checks, copying, and .app packaging as applicable. It then reports provider startup and periodically says which providers are still pending. Do not kill a healthy share merely because packaging or Tailscale setup takes longer than a few seconds.

Once ready, it prints one block for each provider that started successfully:

App: MyApp
Requires: iOS 16.0 or later
Tunnel: Cloudflare Quick Tunnel
Install page: https://<random>.trycloudflare.com/install/artifact-<uuid>
Install link: itms-services://?action=download-manifest&url=...

In auto mode, Tailscale Serve and Funnel blocks appear alongside the Cloudflare block when those CLIs and services are ready. A missing or failed provider is reported as a warning while the other links remain usable. Read the Access: line next to each block: it says Public internet or Tailnet only.

For Android, Requires contains an API level and Install link is the granted HTTPS download.apk URL. Give the user the install page in either case.

Return every ready Install page URL to the user, not just the first or a preferred provider. Label each URL with its provider and access scope (Public internet or Tailnet only) so the user can choose which route to open. A provider warning is not a reason to omit the other successful links. If only one provider becomes ready, return that one and briefly mention that it was the only available route.

The Install page URLs are the ones to open on the phone and paste into a message. Do not substitute the native Install link values. A concise reply with multiple results can look like:

text
- Cloudflare Quick Tunnel (Public internet): https://.../install/...
- Tailscale Serve (Tailnet only): https://.../install/...
- Tailscale Funnel (Public internet): https://.../install/...

The QR code is terminal art printed below that banner. Don't try to reproduce it in your reply — say it's in their terminal and to scan it with the phone camera app. If they're working from a different machine than the one running the command, the URL is what they need.

For a foreground share, mention that the link dies when the command stops. For a background share, mention its expiry instead; the short launcher command has already exited by design.

While it runs

Downloads report themselves:

Downloading MyApp.ipa: 45% (96.5 MB / 214.6 MB)
Download complete: MyApp.ipa (214.6 MB in 38s)
Download interrupted: MyApp.ipa at 62% (133.1 MB / 214.6 MB)

If the user asks whether it worked or asks for the links again, inspect the managed session rather than guessing, and return every ready provider link:

bash
remote-installer status <share-id>
remote-installer logs <share-id>

Silence in the logs means the phone hasn't started downloading — usually that the page hasn't been opened yet, not that anything is broken.

To stop, send Ctrl-C to the share process. It owns tunnel cleanup, so the selected Tailscale Serve/Funnel session or Cloudflare process closes with it. Stop a managed share with remote-installer stop <share-id> so launchd sends a graceful termination signal and closes the worker's tunnels.

When validation fails

Validation runs before the tunnel opens, so these fail locally in about a second with nothing exposed. Each is a real problem with the build:

ErrorMeansFix
app is not an iphoneos device buildSimulator buildUse the -iphoneos product, not -iphonesimulator
IPA app bundle has no _CodeSignature/CodeResourcesUnsignedExport from Xcode properly rather than zipping a Payload folder by hand
has no embedded.mobileprovisionApp Store buildRe-export with a development or ad-hoc profile
embedded provisioning profile has expiredStale profileRefresh in Xcode and rebuild
does not allow bundle identifierProfile is for a different appExport with the matching profile
macOS .app bundles cannot be installed on iOSWrong platformBuild for the iphoneos SDK
CLI was not foundMissing tunnel binarybrew install cloudflared, or pass --cloudflared-bin
Warning: apkanalyzer was not foundMetadata and split checks skippedInstall SDK Command-Line Tools or pass --apkanalyzer-bin
Warning: apksigner was not foundSignature verification skippedInstall SDK Build Tools or pass --apksigner-bin
APK split packages are not supportedNot a standalone APKBuild a signed universal/standalone APK

--allow-unsigned exists for IPA input only. APK signatures are verified when apksigner is available; without it the CLI emits a prominent warning. Reach for the flag only when the user explicitly asks. It fixes nothing — it moves a failure caught in one second on the Mac to a failure the recipient hits after downloading hundreds of megabytes, where the only diagnostic is iOS saying "Unable to Install". Say that plainly instead of reaching for the flag to make an error message go away.

When the install fails on the phone

The tool distributes; it does not sign. "Unable to Install" on the device is nearly always the provisioning profile not listing that device's UDID. Getting the device registered means a rebuild — there is nothing to change on this side.

If an iOS page loads but tapping Install does nothing, use Safari because itms-services:// is handled there. On Android, open the downloaded APK; the system may require enabling “Install unknown apps” for that browser. An update also requires the same signing certificate as the installed app.

Worth telling the user once

  • A public install URL is an opaque capability link: there is no listing or password, but anyone with the complete Cloudflare or Funnel URL can install and forward it. Serve additionally requires tailnet access. --timeout and --max-downloads bound the share.
  • The normal path validates an already signed build before exposure and serves only its temporary staged copy, not the repository. Signing does not make the build confidential or harmless if the URL leaks.
  • Cloudflare Quick Tunnel terminates TLS at Cloudflare while the build is transferred. Tailscale Serve keeps the link private to the tailnet; Tailscale Funnel provides a public link.
  • Cloudflare Quick Tunnel hostnames are random and new on every run, so a link can't be bookmarked or reused tomorrow.

© icodesign, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in skills/remote-installer of icodesign/remote-installer.

Open the folder on GitHubat commit fbeb81e

Compare with similar skills

Remote Installer next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Remote Installer compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Remote Installer this skillicodesign/remote-installer106—~4kAutomated safety check: PassMIT
OdevioOdevio/Odevio-CLI423—~7.6kAutomated safety check: PassMIT
iOS App Store SubmitZestfulPulse/ios-app-store-submit142—~4.7kAutomated safety check: PassMIT
Expo Deploymentkingstinct/react-native-healthkit7154 repos~930Automated safety check: PassMIT
Asc Xcode Buildrorkai/app-store-connect-cli-skills1.1k2 repos~2.1kAutomated safety check: PassMIT
Deploy iOStimusus/Shuttle2229—~1.1kAutomated safety check: PassApache-2.0

Similar skills

  • Odevio

    Odevio/Odevio-CLI

    Take a Flutter project to an iPhone or the App Store with Odevio - build, sign and publish iOS apps from Windows, Linux or macOS with no Mac and no Xcode.

    423 GitHub stars~7.6k tokensUpdated 13 days ago
    MobileAuto-check passed
  • iOS App Store Submit

    ZestfulPulse/ios-app-store-submit

    Build, sign, and submit a Flutter/iOS app to the App Store Connect — covers Xcode archive/export, code signing (including headless-Mac keychain workarounds), the asc CLI for App Store Connect…

    142 GitHub stars~4.7k tokensUpdated 6 days ago
    MobileAuto-check passed
  • Expo Deployment

    kingstinct/react-native-healthkit

    Deploying Expo apps to iOS App Store, Android Play Store, web hosting, and API routes

    715 GitHub starsUsed in 4 repos~930 tokens
    MobileAuto-check passed
  • Asc Xcode Build

    rorkai/app-store-connect-cli-skills

    Build, archive, generate export options, export, upload, and manage Xcode version/build numbers with the current asc xcode helpers.

    1.1k GitHub starsUsed in 2 repos~2.1k tokens
    MobileAuto-check passed
  • Deploy iOS

    timusus/Shuttle2

    Deploy Shuttle Music for iOS to TestFlight from this Mac. An agent skill from timusus/Shuttle2.

    229 GitHub stars~1.1k tokensUpdated yesterday
    MobileAuto-check passed
  • Testflight Release

    termio-sh/termio

    Ship a new TestFlight build of the iOS companion (TermioMobile) — resolve the next build number against App Store Connect, archive, sign, export, upload, write the What to Test notes, and distribute.

    540 GitHub stars~2.5k tokensUpdated yesterday
    MobileAuto-check: warnings

Categories

Questions about Remote Installer

What does Remote Installer do?

Put an iOS or Android build on a real phone or tablet over the air with the remote-installer CLI — it validates the build, opens a temporary HTTPS tunnel, and prints one or more install URLs plus QR…. Remote Installer is an agent skill from icodesign/remote-installer. Put an iOS or Android build on a real phone or tablet over the air with the remote-installer CLI — it validates the build, opens a temporary HTTPS tunnel, and prints one or more install URLs plus QR codes to scan.

When should I use Remote Installer?

Remote Installer fits situations like: someone has just finished an Xcode; android build and asks how to get it onto a device.

How do I install Remote Installer in Claude Code?

Run `npx skills add icodesign/remote-installer --skill remote-installer -a claude-code`. Or copy the skill folder (skills/remote-installer in icodesign/remote-installer) into .claude/skills/remote-installer in your project. Claude Code loads it when a task matches its description.

How do I install Remote Installer in Codex?

Run `npx skills add icodesign/remote-installer --skill remote-installer -a codex`. Or copy the skill folder (skills/remote-installer in icodesign/remote-installer) into .agents/skills/remote-installer in your project. Codex loads it when a task matches its description.

Can I use Remote Installer in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add icodesign/remote-installer --skill remote-installer -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/remote-installer, .gemini/skills/remote-installer, .github/skills/remote-installer and .opencode/skills/remote-installer in your project.

What does Remote Installer need to run?

Going by SKILL.md and its folder, Remote Installer needs the command-line tools its instructions call (brew, npx, xcodebuild and apk). Our summary lists: Node.js.

Does Remote Installer access the network?

SKILL.md contains no URLs. Its commands use npx, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Remote Installer safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Remote Installer use?

Remote Installer is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Remote Installer use?

About 4k tokens (SKILL.md is roughly 16k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Remote Installer?

Skills that share tags, products or a category with Remote Installer: Odevio (Odevio/Odevio-CLI, 423 stars), iOS App Store Submit (ZestfulPulse/ios-app-store-submit, 142 stars), Expo Deployment (kingstinct/react-native-healthkit, 715 stars) and Asc Xcode Build (rorkai/app-store-connect-cli-skills, 1.1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Remote Installer?

icodesign (a GitHub user) maintains it in icodesign/remote-installer, which has 106 GitHub stars. The repository was last updated on September 30, 2026.

Source: icodesign/remote-installer on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.