{"id":14036,"plugin_id":"plugin_asdk_app_6aa95107d094819192324cfe1acf2985","kind":"skill","collection_source":null,"comparison_source":null,"observed_at":"2026-09-30T23:08:40.825Z","digest":"94d9284dd26e8cfb7d855a5e8adee7cf051f804f04383b9d4450c419fab0967f","against":null,"payload":{"name":"limrun-xcode-bazel","description":"Build a Bazel-based iOS / macOS / Apple app on Limrun's remote build execution (RBE) instead of a local Mac, and install it on a remote iOS simulator. Use when the project is a Bazel workspace (MODULE.bazel / WORKSPACE) building rules_apple / rules_swift targets and the user wants to `bazel build` it or run it on a simulator, or when a `--config=limrun` build or install misbehaves. To then tap, type, screenshot, or otherwise interact with the running app, use limrun-ios-simulator. For non-Bazel (plain xcodebuild) projects use limrun-xcode instead.","included_files":[{"relative_path":"references/project-compatibility.md","size_in_bytes":6207},{"relative_path":"references/verify-remote.md","size_in_bytes":2315}],"skill_md_contents":"---\nname: limrun-xcode-bazel\ndescription: \"Build a Bazel-based iOS / macOS / Apple app on Limrun's remote build execution (RBE) instead of a local Mac, and install it on a remote iOS simulator. Use when the project is a Bazel workspace (MODULE.bazel / WORKSPACE) building rules_apple / rules_swift targets and the user wants to `bazel build` it or run it on a simulator, or when a `--config=limrun` build or install misbehaves. To then tap, type, screenshot, or otherwise interact with the running app, use limrun-ios-simulator. For non-Bazel (plain xcodebuild) projects use limrun-xcode instead.\"\nuser-invocable: true\neffort: high\n---\n\n# Bazel iOS builds on Limrun RBE\n\nBuild Bazel Apple projects on Limrun's remote Mac workers — from any environment\n(Linux, Windows, macOS, VM, container), no local Xcode. `lim xcode rbe` brings up\na remote RBE stack, tunnels it to a local port, and writes a `.limrun/` config so\n`bazelisk build --config=limrun` runs Apple actions remotely. Never fall back to\nlocal Xcode or build tools.\n\n## Auth and CLI\n\nInstall if needed: `npm install --global lim`. Auth is `lim login` or\n`LIM_API_KEY` (may be set outside the project — don't ask for it just because\nit's absent). The CLI is the source of truth: the commands in this skill are\nverified, but if a flag errors or you need one not shown here, check\n`lim xcode rbe --help` instead of guessing.\n\n## Build\n\n1. From the **Bazel workspace root** (has `MODULE.bazel` / `WORKSPACE`), run\n   `lim xcode rbe`. It sets up the instance + `.limrun/` config and **prints the\n   exact build command**. The tunnel runs in the background (prints a PID);\n   `--no-daemon` keeps it foreground.\n2. Run the printed command, e.g.\n   `bazelisk --digest_function=sha256 build --config=limrun //App`.\n\nDon't hand-write `.limrun/` or the flags — the CLI generates them for the\nsandbox's Xcode and your OS. `lim xcode version set 27` (or the one-off\n`lim xcode rbe --xcode-version 27`) builds with another installed major. Re-run\n`lim xcode rbe` (after `--stop`) to refresh after a fleet Xcode upgrade or an\nXcode switch.\n\nTo add your own Bazel flags to the limrun path without editing the generated\nconfig, put them in **`user.limrun.bazelrc`** at the workspace root. The\ngenerated config try-imports it last, so your `build:limrun --…` lines win, and\nit survives `lim xcode rbe` regeneration (`.limrun/` does not).\n\n## Run on a simulator\n\n`lim xcode rbe` is build-only; attach a simulator when the user wants to see or\nrun the app. Check or attach (it installs the last build immediately, so no\nrebuild is needed):\n\n```bash\nlim xcode get             # is a simulator already attached?\nlim ios create --attach   # attach one\n```\n\nAdd `--no-open` when you have no browser to show the user; it skips opening\nthe stream URL locally and still prints it for sharing.\n\nIf the attach output includes a signed stream URL, share it with the user as a\nMarkdown link, such as `[Live simulator](<signed-stream-url>)`.\n\nWith a simulator attached, every successful `--config=limrun` build automatically\nreinstalls and relaunches the app, no separate install step:\n\n```bash\nbazelisk --digest_function=sha256 build --config=limrun //App\n```\n\nNotes:\n- **Attach upfront** if you already know you want a sim: `lim xcode rbe --ios`\n  (attaches at startup, removed on `--stop`).\n- Auto-install happens server-side from the build's events; there is no\n  `lim xcode rbe install` subcommand or `--target` flag. To force a reinstall,\n  rebuild (a cache-hit rebuild is seconds).\n- It fires when the successful invocation produced a single app, so in a\n  multi-app workspace build one app target per invocation (`//App`, not\n  `//...`); a multi-app build succeeds but installs nothing.\n\nTo tap, type, read the element tree, screenshot, or record the running app,\nswitch to the **`limrun-ios-simulator`** skill.\n\n## Upload builds as assets\n\nTo publish a build as a Limrun asset (preview links, installing on other\nsimulators, CI artifacts), arm uploads at tunnel start or upload one build\nafter the fact:\n\n```bash\nlim xcode rbe --auto-upload preview/my-app --upload-ttl 24h  # every successful build refreshes the asset\nlim xcode rbe upload preview/my-app --ttl 24h                # one-shot: the newest successful build\n```\n\n- `--auto-upload` holds for the tunnel's lifetime: each successful\n  `--config=limrun` build re-uploads the app under that asset name, no\n  post-build step. Upload results land in `.limrun/rbe.log`.\n- `rbe upload` runs from the workspace root and needs a background tunnel\n  plus at least one successful build; it errors otherwise.\n- TTLs are Go durations (`24h`, `30m`; `1d` is invalid) and optional; each\n  upload without one pushes the asset's expiry to 14 days from that upload.\n- To change the `--auto-upload` config of a running tunnel, `--stop` and\n  re-run; the CLI refuses a mismatched re-arm instead of silently ignoring it.\n- Preview an uploaded app in a browser at\n  `https://console.limrun.com/preview?asset=<name>&platform=ios`.\n\n## Teardown\n\nStop with **`lim xcode rbe --stop`** (~20s to tear the remote stack down) and delete the instance with **`lim xcode delete <id>`**\n\n## Gotchas\n\n- **Always pass `--digest_function=sha256` before `build`** (use the command the\n  CLI prints verbatim). The Limrun cache is SHA256-only; Bazel 9 defaults to\n  BLAKE3. It's a startup flag, so it can't live in `--config=limrun`. Symptoms:\n  build → `Cannot use hash function BLAKE3 with remote cache`; install →\n  `non-SHA256 digest … rebuild with --digest_function=sha256`.\n- **Run `lim xcode rbe` from the workspace root**, not a subdirectory — it writes\n  `.limrun/` there and fails fast otherwise.\n- **A green build doesn't prove remote execution** — cache hits (`action cache\n  hit` / `remote cache hit`) make builds pass even with the tunnel gone. To force\n  and verify real remote execution, see `references/verify-remote.md`.\n- **The printed `.ipa` path won't exist on your machine** — the build command\n  carries `--remote_download_outputs=minimal`, which keeps the artifact in the\n  instance's cache and downloads nothing. Bazel still prints its usual\n  `Target //App:App up-to-date: …/App.ipa` line, but that file is **not** on\n  disk. This is expected, not a failed build. With a simulator attached, the\n  build auto-installs from the artifact's cache digest (read from the build event\n  log, not the local file). Only if you genuinely need the `.ipa` locally, drop\n  `--remote_download_outputs=minimal` from the build command and Bazel downloads\n  the top-level output; auto-install keeps working either way.\n- **A fresh instance can fail the first build with `Lost inputs no longer\n  available remotely`** (e.g. `… Assets.car`). It's a transient cache eviction\n  between instances, not a code error; Bazel prints `Found transient remote cache\n  error, retrying the build...` and the retry succeeds. To avoid hitting it\n  mid-demo, pre-warm with a full build right after `lim xcode rbe`.\n- **`You don't have permission to save … in \"CoreSimulator\"`** (actool/ibtool) is\n  a fleet-side device gap, not your config. Retry; if it persists, report it to\n  Limrun.\n- **The project's own Bazel settings can fight RBE** (Xcode pinned via a Starlark\n  transition, custom `remote_default_exec_properties`, sandbox-hostile genrules).\n  These are per-project, not Limrun bugs — walk\n  `references/project-compatibility.md` before concluding RBE is broken.\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}