Examples
All examples pass --reason "<why>" before the subcommand (not necessary for humans, but required for agents) and use --udid <udid>. (You can omit --udid when exactly one simulator is booted.)
Two ways to run
One-shot (a single submission)
Append a single string of Swift to the subcommand. idb-repl compiles and runs just that code, prints the result, and exits — no /run//exit, no stdin. This is the easiest way to drive a target from a shell or script.
idb-repl --reason "quick math" simulator --udid <udid> 'return "answer: \(6 * 7)"'
The code must still end in a return of the value to surface. Single-quote it so Swift string interpolation (\(...)) passes through untouched.
One-shot is not limited to one line. The trailing argument just has to be a single string — it can hold as much Swift as you like, including your own func, struct, and class definitions, all compiled together and usable within that submission. A single-quoted shell argument can span multiple lines:
idb-repl --reason "multi-line one-shot" simulator --udid <udid> '
func fib(_ n: Int) -> Int { n < 2 ? n : fib(n - 1) + fib(n - 2) }
struct Report { let n: Int; var value: Int { fib(n) } }
let r = Report(n: 10)
return "fib(\(r.n)) = \(r.value)"
'
Interactive
Run a subcommand with no trailing code to get an interactive REPL: type Swift line by line, /run to execute, /exit to quit. See CLI reference → Interactive commands.
Since the Bash tool has no TTY, drive the interactive REPL by piping with printf (note the doubled backslash to escape interpolation for printf):
printf 'let x = 32 * 64\nreturn x\n/run\n/exit\n' \
| idb-repl --reason "interactive demo" simulator --udid <udid> 2>&1
Don't pass a trailing code argument when piping — that switches to one-shot mode and ignores stdin.
Reading the output
-
On success, stdout carries a result block:
Result:
<returned value> -
On failure (e.g. a compile error), stdout carries
Error: <message>instead. -
Either way
idb-replexits 0 — check for theResult:/Error:prefix, not the exit code. -
Diagnostics (interfaces received, the target triple) go to stderr. Redirect with
2>/dev/nullif you only want the result.
Simulator context
Evaluate an expression:
idb-repl --reason "eval" simulator --udid <udid> 'return "\(Date.now)"'
Tap a labelled element, then report how many top-level accessibility children are on screen:
idb-repl --reason "drive UI" simulator --udid <udid> \
'IDB.ui.tap(marker: "Settings"); return IDB.ui.describeAll()?.children.count ?? 0'
Take a screenshot (the returned path is on the companion's filesystem):
idb-repl --reason "screenshot" simulator --udid <udid> \
'return IDB.screenshot.capture() ?? "failed"'
See the built-in IDB API for the full command set.
App context
Run in the bundled empty host app (nothing to install):
idb-repl --reason "get screen size" app --udid <udid> "import UIKit; return UIScreen.main.bounds"
Run inside an installed app's process:
idb-repl --reason "read bundle id" app --udid <udid> --bundle-id com.apple.Maps \
'return Bundle.main.bundleIdentifier ?? "?"'
Scripting a live app across many calls
Because the app context attaches to the same running process by default, you can script an app step by step and keep state between calls:
UDID=<udid>; APP=com.example.app; WHY="scripting the app"
# First call launches; later calls attach to the SAME process (same pid).
idb-repl --reason "$WHY" app --udid $UDID --bundle-id $APP 'return "pid=\(ProcessInfo.processInfo.processIdentifier)"'
idb-repl --reason "$WHY" app --udid $UDID --bundle-id $APP 'IDB.ui.tap(marker: "Settings"); return "tapped"'
idb-repl --reason "$WHY" app --udid $UDID --bundle-id $APP 'return "still \(ProcessInfo.processInfo.processIdentifier)"'
Force a fresh process with --new-session. For long-running sessions, launch with idb launch --enable-repl first — see Writing REPL code → App context.
Test context
Build the .xctest bundle, then run code inside the bundle's process:
BUNDLE=$(buck build <buck-test-target> --show-output 2>/dev/null | awk '{print $2}')
idb-repl --reason "run in test bundle" test --udid <udid> --test-bundle-path "$BUNDLE" \
'return "loaded \(Bundle.allBundles.count) bundles"'
Remote companion
Connect directly to an already-running (typically remote) companion, bypassing discovery:
idb-repl --reason "remote" app --companion <host:port> 'return "attached to remote"'
# add --plaintext to force an unencrypted connection
Recording and replaying
Write a Markdown report of a session, then replay it later:
# Record.
idb-repl --reason "record" app --udid <udid> --bundle-id com.example.app \
--report-path /tmp/session.md 'IDB.ui.tap(marker: "Settings"); return "step 1"'
# Replay.
idb-repl replay --udid <udid> /tmp/session.md
See Reports and replay for the details.