This PR makes Linux work.
# AI Summary
<details>
Brings Argent up on Linux as a host: per-platform npm bundle, renderer
selection that actually works on hybrid-GPU / Wayland / containerized
Linux, hot-boot guarding that survives the SwiftShader composite gap, a
real Linux preflight, and a Wayland-headless E2E job in CI. macOS stays
on
the path it was on before (no `-gpu` flag was passed; AVD config
decided);
nothing about the iOS Simulator behavior changes.
The diff is broader than "ship the Linux artifact" — calling it out
below
because several pieces affect macOS too and reviewers should be primed
for
that rather than skim past expecting "just packaging."
### What's actually in here
**npm packaging (the original framing — still load-bearing)**
| File | Change |
|---|---|
| `packages/argent/scripts/argent-simulator-server.cjs` (new) | Node
dispatcher exposed as the `argent-simulator-server` bin entry. Joins
`process.platform` into the bin path and execs. Forwards
SIGTERM/SIGINT/SIGHUP parent→child so non-TTY supervisors can't orphan
the binary. |
| `packages/argent/scripts/bundle-tools.cjs` | Copies per-platform
binaries from `packages/native-devtools-ios/bin/<platform>/` into
`packages/argent/bin/<platform>/`. darwin required, linux best-effort. |
| `packages/argent/package.json` | `bin.argent-simulator-server` points
at the dispatcher. |
| `packages/native-devtools-ios/src/index.ts` | Resolver joins
`process.platform` into the simulator-server bin path. iOS-only dylibs
and `ax-service` throw `"requires a macOS host"` on Linux callers so
they get the root cause, not "file not found". |
| `scripts/download-simulator-server.sh` | Downloads
`simulator-server-argent-{macos,linux}` into platform-keyed subdirs.
**Purges each platform dir before its download attempt** so a failed
download can't leave stale binaries in place from a prior run. |
| `scripts/dev.cjs` | Local dev copies the current host's binary into
`bin/<process.platform>/` to match the resolver layout. |
| `.github/workflows/publish{,-next}.yml` | Replaces single `test -x
darwin/...` with a per-platform inventory loop. darwin always required;
Linux gated by `ARGENT_REQUIRE_LINUX_BINARY=1` (flip once radon#118
lands). |
**Linux runtime — emulator boot path**
| File | Change |
|---|---|
| `packages/tool-server/src/tools/devices/boot-device.ts` |
`selectGpuMode()`: Linux defaults to `-gpu swiftshader` (`auto` lands on
lavapipe with ~10× cold-boot slowdown; `-gpu host` produces silent
black-window failures on Optimus / NVIDIA+libglvnd / Wayland-on-hybrid /
containers). macOS keeps `auto` (ANGLE→Metal).
`ARGENT_EMULATOR_GPU_MODE` overrides, **validated against `emulator
-help-gpu`'s whitelist** so a typoed value fails fast instead of burning
the whole boot budget. `ARGENT_EMULATOR_NO_WINDOW=1` appends
`-no-window` for headless contexts (CI / containers / Wayland sessions
with no Qt wayland plugin). |
| `packages/tool-server/src/tools/devices/boot-device.ts` (cont.) |
**Cold-boot:** `awaitFirstRealFrame` polls SwiftShader's lockscreen
composite (PNG byte-count via `screencap -p`); blocks `booted:true`
until a real frame shows up. Without this, callers chaining `boot-device
→ screenshot` get an all-black PNG because `sys.boot_completed=1` fires
5–60 s before the first composite. |
| `packages/tool-server/src/tools/devices/boot-device.ts` (cont.) |
**Hot-boot:** `assertScreencapAlive` polls within an 8 s budget instead
of single-probing. The earlier single-probe caught the sticky-blank
state but also killed the emulator on every transient snapshot-restore
blank, forcing "every boot is cold" cycles. Sticky vs transient is
discriminated by whether the budget exhausts. |
| `packages/tool-server/src/utils/linux-preflight.ts` (new) |
`linuxBootDiagnostics()` checks `/dev/kvm` access. `diagnoseAvdSizing()`
warns when a target AVD's `hw.ramSize`/`vm.heapSize` is below the floor
an aggressive RN/Expo app needs (2G/228M avdmanager defaults wedge under
load). |
| `packages/tool-server/src/utils/android-binary.ts` |
`defaultAndroidRoots()` probes typical SDK install locations when
`ANDROID_HOME`/`ANDROID_SDK_ROOT` are unset — **cross-platform**,
benefits macOS launches from GUI-launched MCP hosts (Claude Code Desktop
etc.) where shell rc env doesn't propagate. |
**Cross-platform fixes that landed alongside**
| File | Change |
|---|---|
| `packages/argent-installer/src/utils.ts` | `getLatestVersion()` now
redirects `npm view`'s stderr to `ignore` so `EBADDEVENGINES` warnings
from a consumer project's `package.json` (e.g. Bluesky's pnpm pin) don't
leak to the user's terminal. **Cross-platform fix**, not Linux-specific.
|
**CI**
| File | Change |
|---|---|
| `.github/workflows/wayland-e2e.yml` (new) | Boots an AVD through the
tool-server under headless Weston; asserts `hw.gpu.mode = swiftshader`
and that screenshots + gesture-tap work without a display. Currently
runs on `pull_request` for the affected paths + `workflow_dispatch`.
Pinned to `radon-daily` for the simulator-server until radon#118 ships a
Linux asset to `radon-main`. |
### Tests added in this PR
- `packages/argent/test/dispatcher.test.ts` — e2e against tmpdir-staged
dispatcher + fake `<platform>/simulator-server`: missing-binary error
path, exit-code passthrough, argv passthrough, SIGTERM forwarding.
- `packages/tool-server/test/native-devtools-ios-resolver.test.ts` —
`requireDarwin` gates for dylibs and `ax-service` on Linux, per-platform
`simulator-server` path resolution, missing-binary error,
`ARGENT_NATIVE_DEVTOOLS_DIR` override.
- `packages/tool-server/test/linux-preflight.test.ts` — KVM diagnostic
shape + `diagnoseAvdSizing` (ram low, heap low, both, neither, missing
keys).
- `packages/tool-server/test/boot-device-hotboot.test.ts` — extended
with `it.each([linux→swiftshader, darwin→auto])` so a single CI runner
exercises both GPU branches (was runner-platform-dependent, regressions
could pass on both runners individually). New cases for the wedged-frame
fallback (under fake timers because the polling budget is short but
real-time enough to exceed vitest's 5 s default), the GPU-mode whitelist
rejection, and the cold-boot composite-wait timeout.
- `packages/tool-server/test/android-binary.test.ts` — extended for
`defaultAndroidRoots` probe ordering and HOME pinning.
### Verification
- `tsc --build`: clean apart from pre-existing
`@argent/native-devtools-android` import errors unrelated to this
branch.
- `vitest run` in `packages/tool-server` and `packages/argent`: 689 + 11
= 700 tests passing; the 4 pre-existing test-file load failures
(native-devtools-android missing) reproduce on `main` and are out of
scope.
- `npm pack -w @swmansion/argent`: produces `swmansion-argent-0.8.0.tgz`
with the per-platform layout.
- Wayland-e2e: triggered on this branch — link will be in a PR comment
once the run completes.
- Manually verified end-to-end on a Wayland-on-hybrid-GPU developer
laptop: AVD boots through the tool-server with `-gpu swiftshader`,
screencap returns real frames, gesture tools work.
### Dependencies / what still gates this
- **radon#118** must land before the Linux artifact ships through the
default channel. The download script tolerates the asset being absent
today (best-effort), so this PR is technically safe to merge before —
Linux installs just won't get a working `simulator-server` until the
upstream artifact is published. Once it lands:
- Drop the `radon-daily` arg in `.github/workflows/wayland-e2e.yml`.
- Flip `ARGENT_REQUIRE_LINUX_BINARY` to `1` in both publish workflows.
- **wayland-e2e is not a required status check** today (no branch
protection on `main` requires it). Worth turning on before merging
anything else that touches the Linux boot path.
### Related
- radon#118 — produces the `simulator-server-argent-linux` artifact this
PR consumes.
- argent-private#11 — cross-builds the iOS Simulator dylibs on Linux.
Strictly orthogonal: those dylibs are macOS-runtime-only regardless of
where they're built, and this PR keeps them under `dylibs/` with a clean
error path on Linux callers.
</details>
Fixes #246
9.6 KiB
Argent is an agentic toolkit that gives your AI assistant direct access to iOS Simulators and Android Emulators. Ask it to tap a button, run a profiler or reproduce an issue manually - all from within your CLI, without switching context.
npx @swmansion/argent init
Capabilities
- Autonomous iOS and Android development - Allow your agent to work with iOS and Android apps on its own - let it build, open, interact with the app and debug it. Ask for reproducing issues, testing features manually, profiling your app and much more, without ever interrupting your work.
- UI interaction - Give your agent full control toolkit - tapping, swiping, pinching, typing, gestures, hardware buttons and all other gears included. Let it navigate your app exactly as a user would, without lifting a finger.
- Profiling with batteries included - Argent can perform and analyze both React-Native and Xcode Instruments profiling sessions. Get comprehensive summaries and ask to optimise your app where you find fit.
- Debugging and diagnostics - Let your agent inspect logs, capture crash reports, and reproduce failing states on the simulator, so you can jump straight to the fix.
- React Native out of the box - Argent works with React Native apps natively, so your agent can build, launch, and iterate on your RN project the same way it would any native app - no extra setup required.
Tip: Once installed, ask your assistant "What can Argent do?" - it will walk you through all capabilities available.
Installation
Prerequisites
- Node.js 18 or later
- For iOS: macOS with Xcode installed
- For Android: Android SDK Platform Tools (
adb) onPATH, and the Android Emulator package if you want to boot AVDs from Argent. Create AVDs via Android Studio oravdmanager.
Linux host: extra prerequisites for Android emulators
Argent runs Android emulators on Linux but the default install can be slow if a few host-side knobs aren't right. Cover these once and the experience matches macOS:
-
KVM access. The emulator falls back to slow software emulation (TCG) without
/dev/kvm. Make sure virtualization is enabled in BIOS/UEFI (vmxfor Intel,svmfor AMD in/proc/cpuinfo) and that your user can read/write/dev/kvm— on most distros that means joining thekvmgroup:sudo usermod -aG kvm "$USER" # log out and back in so the new group takes effect -
GPU mode (
-gpu swiftshaderon Linux, override available). The Android emulator's Linux GPU story is messy:-gpu autofrequently resolves to lavapipe (slow software Vulkan via host libvulkan, ~10× cold-boot regression on flagship hardware), and-gpu hostsilently produces a corrupted or black emulator window on hosts with non-trivial GL stacks — dual-GPU / Optimus laptops, NVIDIA + Mesa coexistence via libglvnd, Wayland sessions on hybrid graphics, headless / containerized hosts. The failure mode is invisible to argent's framebuffer-based screenshot tool, so an agent reports success while the developer sees a black window.Argent picks
-gpu swiftshaderon Linux for universal compatibility: it sidesteps the host GL stack entirely and renders via the emulator's bundled SwiftShader. On modern multi-core machines this is indistinguishably smooth from hardware-accelerated-gpu host(and far faster than lavapipe).Override with the
ARGENT_EMULATOR_GPU_MODEenv var if you've verified-gpu hostworks on your machine (typical single-GPU Mesa box with a healthy X session):ARGENT_EMULATOR_GPU_MODE=host argent ...Argent's boot-device preflight prints a warning if
/dev/kvmisn't usable — the condition that causes a 10–50× TCG-vs-KVM slowdown. -
System image. Prefer the
defaultorgoogle_apisvariants ofx86_64system images for headless agent workflows;google_apis_playstoreadds noticeable boot-time CPU churn from Play services. Always pickx86_64on Intel/AMD hosts — ARM images run via QEMU translation and are dramatically slower. -
AVD config. AVDs created via
avdmanager create avddefault tohw.gpu.enabled=no. Argent overrides this with an explicit-gpuarg at launch (so the on-disk config doesn't need editing). For the smoothest experience under heavy native builds (gradle compilations alongside the AVD), bump the AVD's RAM and CPU count — edit~/.android/avd/<name>.avd/config.ini:hw.ramSize = 8192 hw.cpu.ncore = 6 vm.heapSize = 512Stock 2 GB / 4 vCPU AVDs can be CPU-starved into wedged-system_server states by a concurrent gradle/Kotlin compile.
-
Headless / CI mode (
ARGENT_EMULATOR_NO_WINDOW=1). Argent shows the emulator window by default so a local developer can see the AVD UI. In a headless context — CI runner, container, or a Wayland-only session where the emulator's bundled Qt has nowaylandplatform plugin and SIGABRTs on the crash-consent dialog — opt out by exportingARGENT_EMULATOR_NO_WINDOW=1before starting the tool-server. This appends-no-windowto the spawn args, selectingqemu-system-x86_64-headlesswhich doesn't need a Qt window. Argent's screencap-based screenshot tool reads the in-memory framebuffer correctly without a visible window.
Run init in your project
From your project root:
npx @swmansion/argent init
This command triggers an installation wizard which:
- Installs
@swmansion/argentglobally - Detects your editor and registers the MCP server
- Copies skills, rules, and agent definitions into your workspace
Prefer a manual install?
npm install -g @swmansion/argent
argent init
CLI Reference
| Command | Description |
|---|---|
argent init |
Install globally and configure MCP in the current workspace |
argent install |
Alias for init command |
argent update |
Pull the latest version and refresh workspace configuration |
argent remove |
Unregister the MCP server and uninstall the package |
argent uninstall |
Alias for remove command |
argent mcp |
Start MCP server instance, used internally by agent |
argent enable |
Enable a predefined feature flag (--scope project for project-local) |
argent disable |
Disable a feature flag (--scope project for project-local) |
argent flags |
List available feature flags and their state |
Supported Editors
argent init auto-detects and configures MCP for:
| Editor | Config location |
|---|---|
| Claude Code | .mcp.json (project) or ~/.claude.json (global) |
| Cursor | .cursor/mcp.json (project) or ~/.cursor/mcp.json (global) |
| VS Code | .vscode/mcp.json |
| Windsurf | .windsurf/mcp.json |
| Zed | .zed/settings.json |
| Gemini CLI | .gemini/settings.json |
| Codex CLI | .codex/config.yaml |
| opencode | opencode.json (project) or ~/.config/opencode/opencode.json (global) |
Privacy
Argent does not collect or transmit any user data. No telemetry, no analytics, no crash reporting.
- Argent integrates with your agent locally over MCP stdio.
- Its internal tools are not reachable from outside your machine.
- The only outbound network call we make is the version check against our public npm package, which sends no user data and fails gracefully if blocked.
License
Argent uses a mixed licensing model.
Source code is released under the Apache License 2.0.
Proprietary binaries (the per-platform bin/<platform>/simulator-server and bin/darwin/ax-service executables and the .dylib files in native-devtools-ios) are the intellectual property of Software Mansion S.A. and are licensed solely for use within this project. Decompiling, reverse-engineering, or redistributing them without explicit written permission is prohibited.
By using Argent, you acknowledge and agree to this structure. See LICENSE for full details.
Argent is created by Software Mansion
Since 2012 Software Mansion is a software agency with experience in building web and mobile apps. We are Core React Native Contributors and experts in dealing with all kinds of React Native issues. We can help you build your next dream product – Hire us.
