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.
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…
$ npx skills add icodesign/remote-installer --skill remote-installer -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install icodesign/remote-installer remote-installer --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ 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-srcUse ~/.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/
Install the "remote-installer" agent skill from https://github.com/icodesign/remote-installer/tree/main/skills/remote-installer into .claude/skills/remote-installer/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "remote-installer", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/icodesign/remote-installer/tree/main/skills/remote-installerType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add icodesign/remote-installer --skill remote-installer -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install icodesign/remote-installer remote-installer --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/icodesign/remote-installer.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/remote-installer .agents/skills/remote-installer && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "remote-installer" agent skill from https://github.com/icodesign/remote-installer/tree/main/skills/remote-installer into .agents/skills/remote-installer/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "remote-installer", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add icodesign/remote-installer --skill remote-installer -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install icodesign/remote-installer remote-installer --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/icodesign/remote-installer.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/remote-installer .cursor/skills/remote-installer && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "remote-installer" agent skill from https://github.com/icodesign/remote-installer/tree/main/skills/remote-installer into .cursor/skills/remote-installer/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "remote-installer", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/icodesign/remote-installer.git --path skills/remote-installer--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add icodesign/remote-installer --skill remote-installer -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install icodesign/remote-installer remote-installer --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/icodesign/remote-installer.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/remote-installer .gemini/skills/remote-installer && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "remote-installer" agent skill from https://github.com/icodesign/remote-installer/tree/main/skills/remote-installer into .gemini/skills/remote-installer/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "remote-installer", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install icodesign/remote-installer remote-installerInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add icodesign/remote-installer --skill remote-installer -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/icodesign/remote-installer.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/remote-installer .github/skills/remote-installer && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "remote-installer" agent skill from https://github.com/icodesign/remote-installer/tree/main/skills/remote-installer into .github/skills/remote-installer/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "remote-installer", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add icodesign/remote-installer --skill remote-installer -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install icodesign/remote-installer remote-installer --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/icodesign/remote-installer.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/remote-installer .opencode/skills/remote-installer && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "remote-installer" agent skill from https://github.com/icodesign/remote-installer/tree/main/skills/remote-installer into .opencode/skills/remote-installer/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "remote-installer", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
remote-installerPut 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. 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.
Read from SKILL.md and the folder at commit fbeb81e. It shows what the files ask for, not the result of running them.
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.
Shell commands in SKILL.md call:
brewnpxxcodebuildapkFrom the folder's file list and the shell code blocks in SKILL.md.
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.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
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.
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.
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.
The full file from icodesign/remote-installer at commit fbeb81e, republished under its MIT licence (© icodesign). 2,065 words, ~4,044 tokens.
.claude/skills/remote-installer/SKILL.md (or your agent's skills folder).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.
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.
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:
.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.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.xcarchive's Products/Applications/<App>.appxcodebuild -exportArchive put the .ipaA 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.
Run it in the foreground when the terminal will stay attached for the whole share:
remote-installer share /path/to/MyApp.ipaFor the normal agent workflow, keep the share alive across turns with the managed background mode:
remote-installer share /path/to/MyApp.ipa \
--background --expire-after 30m --jsonThis 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.
remote-installer share /path/to/MyApp.ipa --timeout 3600Tighten it when the context implies something narrower — one named tester or a build that should have a short sharing window:
remote-installer share /path/to/MyApp.ipa --timeout 900 --max-downloads 1The 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.
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:
- 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.
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:
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.
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:
| Error | Means | Fix |
|---|---|---|
app is not an iphoneos device build | Simulator build | Use the -iphoneos product, not -iphonesimulator |
IPA app bundle has no _CodeSignature/CodeResources | Unsigned | Export from Xcode properly rather than zipping a Payload folder by hand |
has no embedded.mobileprovision | App Store build | Re-export with a development or ad-hoc profile |
embedded provisioning profile has expired | Stale profile | Refresh in Xcode and rebuild |
does not allow bundle identifier | Profile is for a different app | Export with the matching profile |
macOS .app bundles cannot be installed on iOS | Wrong platform | Build for the iphoneos SDK |
CLI was not found | Missing tunnel binary | brew install cloudflared, or pass --cloudflared-bin |
Warning: apkanalyzer was not found | Metadata and split checks skipped | Install SDK Command-Line Tools or pass --apkanalyzer-bin |
Warning: apksigner was not found | Signature verification skipped | Install SDK Build Tools or pass --apksigner-bin |
APK split packages are not supported | Not a standalone APK | Build 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.
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.
--timeout and
--max-downloads bound the share.© icodesign, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in skills/remote-installer of icodesign/remote-installer.
Open the folder on GitHubat commit fbeb81e
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.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Remote Installer this skillicodesign/remote-installer | 106 | — | ~4k | Automated safety check: Pass | MIT | |
| OdevioOdevio/Odevio-CLI | 423 | — | ~7.6k | Automated safety check: Pass | MIT | |
| iOS App Store SubmitZestfulPulse/ios-app-store-submit | 142 | — | ~4.7k | Automated safety check: Pass | MIT | |
| Expo Deploymentkingstinct/react-native-healthkit | 715 | 4 repos | ~930 | Automated safety check: Pass | MIT | |
| Asc Xcode Buildrorkai/app-store-connect-cli-skills | 1.1k | 2 repos | ~2.1k | Automated safety check: Pass | MIT | |
| Deploy iOStimusus/Shuttle2 | 229 | — | ~1.1k | Automated safety check: Pass | Apache-2.0 |
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.
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…
kingstinct/react-native-healthkit
Deploying Expo apps to iOS App Store, Android Play Store, web hosting, and API routes
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.
timusus/Shuttle2
Deploy Shuttle Music for iOS to TestFlight from this Mac. An agent skill from timusus/Shuttle2.
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.
Categories
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.
Remote Installer fits situations like: someone has just finished an Xcode; android build and asks how to get it onto a device.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.