DeviceTerm
DeviceTerm is a macOS terminal that runs live Apple device panes beside your shell. The tab is the workspace: one shell, plus the device panes that tab owns.
Authored against deviceterm 0.6.0. The CLI is the authority. Where this
skill and deviceterm help <verb> disagree, believe the binary and say so.
Confirm you are in a tab before anything else
printf '%s\n' "${DEVICETERM_SESSION:-NOT-IN-A-DEVICETERM-TAB}"
If that prints the sentinel, this shell is not a DeviceTerm tab. Say so plainly and stop. No device control is available from here, and no flag changes that.
Inside a tab four variables are set: DEVICETERM_SESSION,
DEVICETERM_SESSION_CAP, DEVICETERM_DAEMON_SOCK, and DEVICETERM_SHIM_DIR.
The CLI reads them itself. No verb takes a credential, so never pass one as an
argument, and never strip these from a subprocess environment.
How a device gets into a tab
Pane attachment is shim-driven. xcrun simctl boot <UDID> run inside a tab
hits DeviceTerm's shim first, which asks the daemon to attach the booted
Simulator to that tab. A Simulator booted anywhere else stays invisible to
deviceterm panes list however healthy it is.
When an input command reports no device pane, check in this order:
deviceterm panes list
which xcrun
deviceterm doctor
which xcrun must resolve inside $DEVICETERM_SHIM_DIR. If it resolves to
/usr/bin/xcrun, the shim is not first on PATH and boots are not being
intercepted; open a fresh tab.
deviceterm device attach <ref> is the explicit path for a Simulator booted
elsewhere, and for mirroring a connected iPhone or iPad.
Division of labor
The deviceterm CLI owns input, accessibility, and the workspace: tap,
swipe, long-press, pinch, app-switcher, button, key, text,
rotate, crown, ax tree|point|sweep, panes, tabs, windows, events, and
doctor.
Apple's tools own the device's lifecycle and content. The verbs below do not exist in deviceterm. Do not go looking for them.
| What you want | What to run |
|---|---|
| Screenshot or video | xcrun simctl io <udid> screenshot / recordVideo |
| Install or launch an app | xcrun simctl install / launch |
| Set location | xcrun simctl location |
| Send a push notification | xcrun simctl push |
| Light/dark, Dynamic Type, status bar | xcrun simctl ui / status_bar |
| Device logs | xcrun simctl spawn <udid> log |
| Every Simulator on the machine | xcrun simctl list devices |
deviceterm devices list reports only what DeviceTerm owns or is mirroring, so
it is not a substitute for simctl list.
On a physical device none of those simctl commands apply. xcrun devicectl is the counterpart, and it covers most of the same ground under
different names: device capture screenshot, device install app,
device process launch, device settings appearance,
device simulate location, and device simulate statusBar. Permission state
and Dynamic Type have no counterpart there.
Run simctl and devicectl from inside the tab, so the shim can attribute
what they do.
Read the reference before composing a command
deviceterm help # every verb, one line each
deviceterm help <verb> # the full reference for one verb
deviceterm agents # workflow and triage guide, organized by task
deviceterm doctor # env, shim, socket, session, and pane diagnosis
deviceterm agents carries the traps: why a swipe collapsed into a tap, why a
crown rotation did nothing, why an accessibility tree came back empty. Read it
when debugging one of those instead of guessing.
Prefer a verb over a script or a jq pipeline wherever one carries the
step. A bare deviceterm <verb> reduces to a durable approval prefix, so it
prompts once rather than on every call, and it keeps rules like coordinate
normalization in the CLI instead of copied into each recipe. The blocking
wait verbs in particular replace hand-rolled poll loops, and they report
which thing failed where a loop can only report that nothing happened yet.
Reading output
--jsonworks on lists and receipts.axandeventsare always JSON.- Typed failures emit a newline-terminated
{"error": …}object on stdout under--json, and on the AX commands even without it. The human diagnostic still goes to stderr and the exit status is still nonzero, so check the status first — but the machine-readable half is there. Branch on.error.code, never on.error.messageor stderr prose. A few command-specific failures predate the typed contract and still produce empty stdout, so handle a missing envelope rather than assuming one. - Absent optional fields are omitted, not null. Test with
jq 'has("shortId")'. - A receipt means the daemon accepted the dispatch. It is not evidence that the effect happened. Read state back to confirm.
- deviceterm prints UDIDs lowercase and
simctlprints them uppercase. Compare case-insensitively across that boundary.
Authority
A live automation grant is created only by a person, through Shell > Open Automation Tab. Three tiers need it, and the difference matters:
- Always. Seven verbs are refused without a grant no matter what they
target:
tab open,tab select,tab move,window open,window focus,tab send-input, andtab capture. - Outside your own tab.
tab renameand the pane verbs are allowed on a tab you own a terminal in, and need a grant for anyone else's. So a cross-tab rename needs one even thoughtab renameis not in the list above. tab closeadditionally needs your tab to be the sole terminal, because the trust unit is the session and a tab can hold several.
Reading tier 1 as the whole rule is the trap: it suggests everything else is unrestricted across tabs, and it is not.
There is no CLI escalation path, so a script cannot grant itself authority and
cannot open its own first tab or window. A refusal arrives as
error.scope_violation, or a message starting intent.automationRequired.
$DEVICETERM_SESSION_ROLE is descriptive metadata, not permission. A verb
listed by deviceterm help can still be refused.
Never shut down a Simulator you did not boot
Do not run xcrun simctl shutdown all, and do not shut down or erase a
Simulator the user booted. Ask first. A Simulator on this machine may belong to
work that has nothing to do with your task.
Related skills
deviceterm-app-verifyfor driving an app and proving what it did.deviceterm-screenshotsfor App Store and marketing captures.deviceterm-a11y-auditfor accessibility sweeps.deviceterm-reprofor reproducing a bug report.deviceterm-tab-titlesfor summarizing and retitling tabs, from an automation tab.